mmc:development
* let busy loops timeout. * Start using interrupt handlers. * Allocate the ramdisk only when used. Change-Id: Ie08d66eefef3c8cd3ee16c04f74a9a50cc12b021
This commit is contained in:
parent
c31c70743a
commit
3de9b14567
6 changed files with 286 additions and 109 deletions
|
@ -6,6 +6,8 @@
|
||||||
#include <minix/driver.h>
|
#include <minix/driver.h>
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
#include <minix/drvlib.h>
|
#include <minix/drvlib.h>
|
||||||
|
#include <minix/minlib.h>
|
||||||
|
|
||||||
|
|
||||||
/* system headers */
|
/* system headers */
|
||||||
#include <sys/ioc_disk.h> /* disk IOCTL's */
|
#include <sys/ioc_disk.h> /* disk IOCTL's */
|
||||||
|
@ -24,25 +26,13 @@
|
||||||
/* used for logging */
|
/* used for logging */
|
||||||
static struct mmclog log = {
|
static struct mmclog log = {
|
||||||
.name = "mmc_block",
|
.name = "mmc_block",
|
||||||
.log_level = LEVEL_DEBUG,
|
.log_level = LEVEL_INFO,
|
||||||
.log_func = default_log
|
.log_func = default_log
|
||||||
};
|
};
|
||||||
|
|
||||||
/* holding the current host controller */
|
/* holding the current host controller */
|
||||||
static struct mmc_host host;
|
static struct mmc_host host;
|
||||||
|
|
||||||
/*@TODO REMOVE THIS */
|
|
||||||
void
|
|
||||||
read_tsc_64(u64_t * t)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
u32_t
|
|
||||||
tsc_64_to_micros(u64_t tsc)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
|
#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
|
||||||
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
|
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
|
||||||
|
|
||||||
|
@ -70,12 +60,18 @@ static void sef_local_startup();
|
||||||
static int block_system_event_cb(int type, sef_init_info_t * info);
|
static int block_system_event_cb(int type, sef_init_info_t * info);
|
||||||
static void block_signal_handler_cb(int signo);
|
static void block_signal_handler_cb(int signo);
|
||||||
|
|
||||||
static int apply_env();
|
void
|
||||||
|
bdr_alarm(clock_t stamp)
|
||||||
|
{
|
||||||
|
mmc_log_debug(&log, "alarm %d\n", stamp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_env();
|
||||||
|
static void hw_intr(unsigned int irqs);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* set the global logging level */
|
/* set the global logging level */
|
||||||
static void set_log_level(int level);
|
static void set_log_level(int level);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Entry points for the BLOCK driver. */
|
/* Entry points for the BLOCK driver. */
|
||||||
static struct blockdriver mmc_driver = {
|
static struct blockdriver mmc_driver = {
|
||||||
|
@ -87,17 +83,25 @@ static struct blockdriver mmc_driver = {
|
||||||
NULL, /* no need to clean up (yet) */
|
NULL, /* no need to clean up (yet) */
|
||||||
block_part, /* return partition information */
|
block_part, /* return partition information */
|
||||||
NULL, /* no geometry */
|
NULL, /* no geometry */
|
||||||
NULL, /* no interrupt processing */
|
hw_intr, /* left over interrupts */
|
||||||
NULL, /* no alarm processing */
|
bdr_alarm, /* no alarm processing */
|
||||||
NULL, /* no processing of other messages */
|
NULL, /* no processing of other messages */
|
||||||
NULL /* no threading support */
|
NULL /* no threading support */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
hw_intr(unsigned int irqs)
|
||||||
|
{
|
||||||
|
mmc_log_debug(&log, "Hardware inter left over\n");
|
||||||
|
host.hw_intr(irqs);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
apply_env()
|
apply_env()
|
||||||
{
|
{
|
||||||
|
long v;
|
||||||
/* apply the env setting passed to this driver parameters accepted
|
/* apply the env setting passed to this driver parameters accepted
|
||||||
* log_level=[0-4] (NONE,WARNING,INFO,DEBUG,TRACE) instance=[0-3]
|
* log_level=[0-4] (NONE,WARN,INFO,DEBUG,TRACE) instance=[0-3]
|
||||||
* instance/bus number to use for this driver Passing these arguments
|
* instance/bus number to use for this driver Passing these arguments
|
||||||
* is done when starting the driver using the service command in the
|
* is done when starting the driver using the service command in the
|
||||||
* following way service up /sbin/mmc -args "log_level=2 instance=1
|
* following way service up /sbin/mmc -args "log_level=2 instance=1
|
||||||
|
@ -115,10 +119,6 @@ apply_env()
|
||||||
} else {
|
} else {
|
||||||
mmc_log_warn(&log, "Unknown driver %s\n", driver);
|
mmc_log_warn(&log, "Unknown driver %s\n", driver);
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
long v;
|
|
||||||
/* The following code(env_parse) uses strtol.c and needs __aeabi_idiv */
|
|
||||||
/* @TODO: re-enable this function when __aeabi_idiv will be present */
|
|
||||||
/* Initialize the verbosity level. */
|
/* Initialize the verbosity level. */
|
||||||
v = 0;
|
v = 0;
|
||||||
if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
|
if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
|
||||||
|
@ -133,7 +133,6 @@ apply_env()
|
||||||
mmc_log_warn(&log, "Failed to set mmc instance to %d\n", v);
|
mmc_log_warn(&log, "Failed to set mmc instance to %d\n", v);
|
||||||
return -1; /* NOT OK */
|
return -1; /* NOT OK */
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,27 +184,27 @@ block_open(dev_t minor, int access)
|
||||||
partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY,
|
partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY,
|
||||||
0 /* atapi device?? */ );
|
0 /* atapi device?? */ );
|
||||||
|
|
||||||
mmc_log_debug(&log, "descr \toffset(bytes) size(bytes)\n", minor);
|
mmc_log_trace(&log, "descr \toffset(bytes) size(bytes)\n", minor);
|
||||||
|
|
||||||
mmc_log_debug(&log, "disk %d\t0x%016llx 0x%016llx\n", i,
|
mmc_log_trace(&log, "disk %d\t0x%016llx 0x%016llx\n", i,
|
||||||
slot->card.part[0].dv_base, slot->card.part[0].dv_size);
|
slot->card.part[0].dv_base, slot->card.part[0].dv_size);
|
||||||
for (i = 1; i < 5; i++) {
|
for (i = 1; i < 5; i++) {
|
||||||
if (slot->card.part[i].dv_size == 0)
|
if (slot->card.part[i].dv_size == 0)
|
||||||
continue;
|
continue;
|
||||||
part_count++;
|
part_count++;
|
||||||
mmc_log_debug(&log, "part %d\t0x%016llx 0x%016llx\n", i,
|
mmc_log_trace(&log, "part %d\t0x%016llx 0x%016llx\n", i,
|
||||||
slot->card.part[i].dv_base, slot->card.part[i].dv_size);
|
slot->card.part[i].dv_base, slot->card.part[i].dv_size);
|
||||||
for (j = 0; j < 4; j++) {
|
for (j = 0; j < 4; j++) {
|
||||||
if (slot->card.subpart[(i - 1) * 4 + j].dv_size == 0)
|
if (slot->card.subpart[(i - 1) * 4 + j].dv_size == 0)
|
||||||
continue;
|
continue;
|
||||||
sub_part_count++;
|
sub_part_count++;
|
||||||
mmc_log_debug(&log,
|
mmc_log_trace(&log,
|
||||||
" sub %d/%d\t0x%016llx 0x%016llx\n", i, j,
|
" sub %d/%d\t0x%016llx 0x%016llx\n", i, j,
|
||||||
slot->card.subpart[(i - 1) * 4 + j].dv_base,
|
slot->card.subpart[(i - 1) * 4 + j].dv_base,
|
||||||
slot->card.subpart[(i - 1) * 4 + j].dv_size);
|
slot->card.subpart[(i - 1) * 4 + j].dv_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mmc_log_info(&log, "Found %d partitions and %d sub partitions\n",
|
mmc_log_debug(&log, "Found %d partitions and %d sub partitions\n",
|
||||||
part_count, sub_part_count);
|
part_count, sub_part_count);
|
||||||
slot->card.open_ct++;
|
slot->card.open_ct++;
|
||||||
assert(slot->card.open_ct == 1);
|
assert(slot->card.open_ct == 1);
|
||||||
|
@ -312,7 +311,7 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
/* Unknown device */
|
/* Unknown device */
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
mmc_log_trace(&log, "I/O %d %s 0x%llx\n", minor,
|
mmc_log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor,
|
||||||
(do_write) ? "Write" : "Read", position);
|
(do_write) ? "Write" : "Read", position);
|
||||||
|
|
||||||
slot = get_slot(minor);
|
slot = get_slot(minor);
|
||||||
|
@ -636,20 +635,18 @@ get_slot(dev_t minor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void
|
static void
|
||||||
set_log_level(int level)
|
set_log_level(int level)
|
||||||
{
|
{
|
||||||
if (level < 0 || level >= 4) {
|
if (level < 0 || level >= 4) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mmc_log_debug(&log, "Setting verbosity level to %d\n", level);
|
mmc_log_info(&log, "Setting verbosity level to %d\n", level);
|
||||||
log.log_level = level;
|
log.log_level = level;
|
||||||
if (host.set_log_level) {
|
if (host.set_log_level) {
|
||||||
host.set_log_level(level);
|
host.set_log_level(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
|
@ -657,7 +654,6 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Set and apply the environment */
|
/* Set and apply the environment */
|
||||||
env_setargs(argc, argv);
|
env_setargs(argc, argv);
|
||||||
|
|
||||||
sef_local_startup();
|
sef_local_startup();
|
||||||
blockdriver_task(&mmc_driver);
|
blockdriver_task(&mmc_driver);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -117,6 +117,9 @@ struct mmc_host
|
||||||
/* Release the card */
|
/* Release the card */
|
||||||
int (*card_release) (struct sd_card * card);
|
int (*card_release) (struct sd_card * card);
|
||||||
|
|
||||||
|
/* Additional hardware interrupts */
|
||||||
|
void (*hw_intr) (unsigned int irqs);
|
||||||
|
|
||||||
/* read count blocks into existing buf */
|
/* read count blocks into existing buf */
|
||||||
int (*read) (struct sd_card * card,
|
int (*read) (struct sd_card * card,
|
||||||
uint32_t blknr, uint32_t count, unsigned char *buf);
|
uint32_t blknr, uint32_t count, unsigned char *buf);
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/* kernel headers */
|
/* kernel headers */
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
|
#include <minix/minlib.h>
|
||||||
|
|
||||||
/* usr headers */
|
/* usr headers */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/* local headers */
|
/* local headers */
|
||||||
#include "mmclog.h"
|
#include "mmclog.h"
|
||||||
|
@ -17,14 +19,14 @@
|
||||||
*/
|
*/
|
||||||
static struct mmclog log = {
|
static struct mmclog log = {
|
||||||
.name = "mmc_host_memory",
|
.name = "mmc_host_memory",
|
||||||
.log_level = LEVEL_TRACE,
|
.log_level = LEVEL_INFO,
|
||||||
.log_func = default_log
|
.log_func = default_log
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is currently a dummy driver using an in-memory structure */
|
/* This is currently a dummy driver using an in-memory structure */
|
||||||
#define DUMMY_SIZE_IN_BLOCKS 0xFFFu
|
#define DUMMY_SIZE_IN_BLOCKS 0xFFFFFu
|
||||||
#define DUMMY_BLOCK_SIZE 512
|
#define DUMMY_BLOCK_SIZE 512
|
||||||
static char dummy_data[DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS];
|
static char *dummy_data = NULL;
|
||||||
|
|
||||||
static struct sd_card *
|
static struct sd_card *
|
||||||
init_dummy_sdcard(struct sd_slot *slot)
|
init_dummy_sdcard(struct sd_slot *slot)
|
||||||
|
@ -35,6 +37,13 @@ init_dummy_sdcard(struct sd_slot *slot)
|
||||||
assert(slot != NULL);
|
assert(slot != NULL);
|
||||||
|
|
||||||
mmc_log_info(&log, "Using a dummy card \n");
|
mmc_log_info(&log, "Using a dummy card \n");
|
||||||
|
if (dummy_data == NULL) {
|
||||||
|
dummy_data = malloc(DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS);
|
||||||
|
if (dummy_data == NULL) {
|
||||||
|
panic
|
||||||
|
("Failed to allocate data for dummy mmc driver\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
card = &slot->card;
|
card = &slot->card;
|
||||||
memset(card, 0, sizeof(struct sd_card));
|
memset(card, 0, sizeof(struct sd_card));
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
#include <minix/com.h>
|
#include <minix/com.h>
|
||||||
#include <minix/vm.h>
|
#include <minix/vm.h>
|
||||||
|
#include <minix/spin.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
/* usr headers */
|
/* usr headers */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -12,6 +14,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/* local headers */
|
/* local headers */
|
||||||
#include "mmclog.h"
|
#include "mmclog.h"
|
||||||
|
@ -25,6 +28,14 @@
|
||||||
/* omap /hardware related */
|
/* omap /hardware related */
|
||||||
#include "omap_mmc.h"
|
#include "omap_mmc.h"
|
||||||
|
|
||||||
|
#define USE_INTR
|
||||||
|
|
||||||
|
#ifdef USE_INTR
|
||||||
|
static int hook_id = 1;
|
||||||
|
#define OMAP3_MMC1_IRQ 83 /* MMC/SD module 1 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SANE_TIMEOUT 500000 /* 500 MS */
|
||||||
/*
|
/*
|
||||||
* Define a structure to be used for logging
|
* Define a structure to be used for logging
|
||||||
*/
|
*/
|
||||||
|
@ -38,14 +49,14 @@ static struct mmclog log = {
|
||||||
#define BIT(x)(0x1 << x)
|
#define BIT(x)(0x1 << x)
|
||||||
|
|
||||||
/* Write a uint32_t value to a memory address. */
|
/* Write a uint32_t value to a memory address. */
|
||||||
inline void
|
static inline void
|
||||||
write32(uint32_t address, uint32_t value)
|
write32(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
REG(address) = value;
|
REG(address) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read an uint32_t from a memory address */
|
/* Read an uint32_t from a memory address */
|
||||||
inline uint32_t
|
static inline uint32_t
|
||||||
read32(uint32_t address)
|
read32(uint32_t address)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -53,7 +64,7 @@ read32(uint32_t address)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set a 32 bits value depending on a mask */
|
/* Set a 32 bits value depending on a mask */
|
||||||
inline void
|
static inline void
|
||||||
set32(uint32_t address, uint32_t mask, uint32_t value)
|
set32(uint32_t address, uint32_t mask, uint32_t value)
|
||||||
{
|
{
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
@ -75,13 +86,11 @@ static uint32_t base_address;
|
||||||
int
|
int
|
||||||
mmchs_init(uint32_t instance)
|
mmchs_init(uint32_t instance)
|
||||||
{
|
{
|
||||||
int counter;
|
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
counter = 0;
|
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|
||||||
struct minix_mem_range mr;
|
struct minix_mem_range mr;
|
||||||
|
spin_t spin;
|
||||||
|
|
||||||
mr.mr_base = MMCHS1_REG_BASE;
|
mr.mr_base = MMCHS1_REG_BASE;
|
||||||
mr.mr_limit = MMCHS1_REG_BASE + 0x400;
|
mr.mr_limit = MMCHS1_REG_BASE + 0x400;
|
||||||
|
@ -106,11 +115,14 @@ mmchs_init(uint32_t instance)
|
||||||
MMCHS_SD_SYSCONFIG_SOFTRESET);
|
MMCHS_SD_SYSCONFIG_SOFTRESET);
|
||||||
|
|
||||||
/* Read sysstatus to know when it's done */
|
/* Read sysstatus to know when it's done */
|
||||||
|
|
||||||
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
|
while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
|
||||||
& MMCHS_SD_SYSSTATUS_RESETDONE)) {
|
& MMCHS_SD_SYSSTATUS_RESETDONE)) {
|
||||||
/* TODO:Add proper delay and escape route */
|
if (spin_check(&spin) == FALSE) {
|
||||||
|
mmc_log_warn(&log, "mmc init timeout\n");
|
||||||
counter++;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set SD default capabilities */
|
/* Set SD default capabilities */
|
||||||
|
@ -164,12 +176,14 @@ mmchs_init(uint32_t instance)
|
||||||
set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP,
|
set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP,
|
||||||
MMCHS_SD_HCTL_SDBP_ON);
|
MMCHS_SD_HCTL_SDBP_ON);
|
||||||
|
|
||||||
/* TODO: Add padconf stuff here as documented in the TRM */
|
// /* TODO: Add padconf/pinmux stuff here as documented in the TRM */
|
||||||
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP)
|
while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP)
|
||||||
!= MMCHS_SD_HCTL_SDBP_ON) {
|
!= MMCHS_SD_HCTL_SDBP_ON) {
|
||||||
/* TODO:Add proper delay and escape route */
|
if (spin_check(&spin) == FALSE) {
|
||||||
counter++;
|
mmc_log_warn(&log, "mmc init timeout SDBP not set\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable internal clock and clock to the card */
|
/* Enable internal clock and clock to the card */
|
||||||
|
@ -177,16 +191,23 @@ mmchs_init(uint32_t instance)
|
||||||
MMCHS_SD_SYSCTL_ICE_EN);
|
MMCHS_SD_SYSCTL_ICE_EN);
|
||||||
|
|
||||||
// @TODO Fix external clock enable , this one is very slow
|
// @TODO Fix external clock enable , this one is very slow
|
||||||
|
// but we first need faster context switching
|
||||||
|
//set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
|
||||||
|
// (0x20 << 6));
|
||||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
|
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
|
||||||
(0x3ff << 6));
|
(0x5 << 6));
|
||||||
|
|
||||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN,
|
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN,
|
||||||
MMCHS_SD_SYSCTL_CEN_EN);
|
MMCHS_SD_SYSCTL_CEN_EN);
|
||||||
counter = 0;
|
|
||||||
|
|
||||||
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS)
|
while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS)
|
||||||
!= MMCHS_SD_SYSCTL_ICS_STABLE) {
|
!= MMCHS_SD_SYSCTL_ICS_STABLE) {
|
||||||
/* TODO:Add proper delay and escape route */
|
|
||||||
counter++;
|
if (spin_check(&spin) == FALSE) {
|
||||||
|
mmc_log_warn(&log, "clock not stable\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -216,7 +237,7 @@ mmchs_init(uint32_t instance)
|
||||||
/* command 0 , type other commands not response etc) */
|
/* command 0 , type other commands not response etc) */
|
||||||
write32(base_address + MMCHS_SD_CMD, 0x00);
|
write32(base_address + MMCHS_SD_CMD, 0x00);
|
||||||
|
|
||||||
counter = 0;
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC)
|
while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC)
|
||||||
!= MMCHS_SD_STAT_CC_RAISED) {
|
!= MMCHS_SD_STAT_CC_RAISED) {
|
||||||
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
||||||
|
@ -225,7 +246,12 @@ mmchs_init(uint32_t instance)
|
||||||
read32(base_address + MMCHS_SD_STAT));
|
read32(base_address + MMCHS_SD_STAT));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
counter++;
|
|
||||||
|
if (spin_check(&spin) == FALSE) {
|
||||||
|
mmc_log_warn(&log,
|
||||||
|
"Interrupt not raised during init\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the cc interrupt status */
|
/* clear the cc interrupt status */
|
||||||
|
@ -238,41 +264,151 @@ mmchs_init(uint32_t instance)
|
||||||
set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
|
set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
|
||||||
MMCHS_SD_CON_INIT_NOINIT);
|
MMCHS_SD_CON_INIT_NOINIT);
|
||||||
|
|
||||||
|
/* Set timeout */
|
||||||
|
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
|
||||||
|
MMCHS_SD_SYSCTL_DTO_2POW27);
|
||||||
|
|
||||||
/* Clean the MMCHS_SD_STAT register */
|
/* Clean the MMCHS_SD_STAT register */
|
||||||
write32(base_address + MMCHS_SD_STAT, 0xffffffffu);
|
write32(base_address + MMCHS_SD_STAT, 0xffffffffu);
|
||||||
|
#ifdef USE_INTR
|
||||||
|
hook_id = 1;
|
||||||
|
if (sys_irqsetpolicy(OMAP3_MMC1_IRQ, 0, &hook_id) != OK) {
|
||||||
|
printf("mmc: couldn't set IRQ policy %d\n", OMAP3_MMC1_IRQ);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* enable signaling from MMC controller towards interrupt controller */
|
||||||
|
write32(base_address + MMCHS_SD_ISE, 0xffffffffu);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mmchs_hw_intr(unsigned int irqs)
|
||||||
|
{
|
||||||
|
mmc_log_warn(&log, "Hardware interrupt left over\n");
|
||||||
|
|
||||||
|
#ifdef USE_INTR
|
||||||
|
if (sys_irqenable(&hook_id) != OK)
|
||||||
|
printf("couldn't re-enable interrupt \n");
|
||||||
|
#endif
|
||||||
|
/* Leftover interrupt(s) received; ack it/them. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* w_intr_wait *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
intr_wait(int mask)
|
||||||
|
{
|
||||||
|
long v;
|
||||||
|
#ifdef USE_INTR
|
||||||
|
if (sys_irqenable(&hook_id) != OK)
|
||||||
|
printf("Failed to enable irqenable irq\n");
|
||||||
|
/* Wait for a task completion interrupt. */
|
||||||
|
message m;
|
||||||
|
int ipc_status;
|
||||||
|
int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
|
||||||
|
|
||||||
|
if (ticks <= 0) ticks =1;
|
||||||
|
while (1) {
|
||||||
|
int rr;
|
||||||
|
sys_setalarm(ticks, 0);
|
||||||
|
if ((rr = driver_receive(ANY, &m, &ipc_status)) != OK) {
|
||||||
|
panic("driver_receive failed: %d", rr);
|
||||||
|
};
|
||||||
|
if (is_ipc_notify(ipc_status)) {
|
||||||
|
switch (_ENDPOINT_P(m.m_source)) {
|
||||||
|
case CLOCK:
|
||||||
|
/* Timeout. */
|
||||||
|
// w_timeout(); /* a.o. set w_status */
|
||||||
|
mmc_log_warn(&log, "TIMEOUT\n");
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case HARDWARE:
|
||||||
|
v = read32(base_address + MMCHS_SD_STAT);
|
||||||
|
if (v & mask) {
|
||||||
|
sys_setalarm(0, 0);
|
||||||
|
return 0;
|
||||||
|
} else if (v & (1 << 15)){
|
||||||
|
return 1; /* error */
|
||||||
|
} else {
|
||||||
|
mmc_log_debug(&log, "unexpected HW interrupt 0x%08x mask 0X%08x\n", v, mask);
|
||||||
|
if (sys_irqenable(&hook_id) != OK)
|
||||||
|
printf
|
||||||
|
("Failed to re-enable irqenable irq\n");
|
||||||
|
continue;
|
||||||
|
// return 1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* unhandled message. queue it and
|
||||||
|
* handle it in the blockdriver loop.
|
||||||
|
*/
|
||||||
|
blockdriver_mq_queue(&m, ipc_status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mmc_log_debug(&log, "Other\n");
|
||||||
|
/*
|
||||||
|
* unhandled message. queue it and handle it in the
|
||||||
|
* blockdriver loop.
|
||||||
|
*/
|
||||||
|
blockdriver_mq_queue(&m, ipc_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sys_setalarm(0, 0); /* cancel the alarm */
|
||||||
|
|
||||||
|
#else
|
||||||
|
spin_t spin;
|
||||||
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
|
/* Wait for completion */
|
||||||
|
int counter =0;
|
||||||
|
while (1 == 1) {
|
||||||
|
counter ++;
|
||||||
|
v = read32(base_address + MMCHS_SD_STAT);
|
||||||
|
if (spin_check(&spin) == FALSE) {
|
||||||
|
mmc_log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",counter, v,mask);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (v & mask) {
|
||||||
|
return 0;
|
||||||
|
} else if (v & 0xFF00) {
|
||||||
|
mmc_log_debug(&log, "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", v, mask);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; /* unreached */
|
||||||
|
#endif /* USE_INTR */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
intr_assert(int mask)
|
||||||
|
{
|
||||||
|
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
||||||
|
mmc_log_debug(&log, "%s, error stat %08x\n", __FUNCTION__,
|
||||||
|
read32(base_address + MMCHS_SD_STAT));
|
||||||
|
set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
|
||||||
|
0xffffffffu);
|
||||||
|
} else {
|
||||||
|
write32(base_address + MMCHS_SD_STAT, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
mmchs_send_cmd(uint32_t command, uint32_t arg)
|
mmchs_send_cmd(uint32_t command, uint32_t arg)
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
/* Read current interrupt status and fail it an interrupt is already
|
/* Read current interrupt status and fail it an interrupt is already
|
||||||
* asserted */
|
* asserted */
|
||||||
if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
|
|
||||||
mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n",
|
|
||||||
__FUNCTION__, read32(base_address + MMCHS_SD_STAT));
|
|
||||||
write32(base_address + MMCHS_SD_STAT,
|
|
||||||
MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
|
||||||
// return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set arguments */
|
/* Set arguments */
|
||||||
write32(base_address + MMCHS_SD_ARG, arg);
|
write32(base_address + MMCHS_SD_ARG, arg);
|
||||||
/* Set command */
|
/* Set command */
|
||||||
set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command);
|
set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command);
|
||||||
|
|
||||||
/* Wait for completion */
|
if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||||
while ((read32(base_address + MMCHS_SD_STAT) & 0xffffu) == 0x0) {
|
intr_assert(MMCHS_SD_STAT_CC);
|
||||||
count++;
|
mmc_log_warn(&log, "Failure waiting for interrupt\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
|
|
||||||
mmc_log_warn(&log, "%s, error stat %08x\n", __FUNCTION__,
|
|
||||||
read32(base_address + MMCHS_SD_STAT));
|
|
||||||
set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
|
|
||||||
0xffffffffu);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,16 +417,20 @@ mmchs_send_cmd(uint32_t command, uint32_t arg)
|
||||||
/*
|
/*
|
||||||
* Command with busy response *CAN* also set the TC bit if they exit busy
|
* Command with busy response *CAN* also set the TC bit if they exit busy
|
||||||
*/
|
*/
|
||||||
while ((read32(base_address + MMCHS_SD_STAT)
|
if ((read32(base_address + MMCHS_SD_STAT)
|
||||||
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
|
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
|
||||||
count++;
|
mmc_log_warn(&log, "TC should be raised\n");
|
||||||
}
|
}
|
||||||
write32(base_address + MMCHS_SD_STAT,
|
write32(base_address + MMCHS_SD_STAT,
|
||||||
MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||||
}
|
|
||||||
|
|
||||||
/* clear the cc status */
|
if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
intr_assert(MMCHS_SD_STAT_CC);
|
||||||
|
mmc_log_warn(&log, "Failure waiting for clear\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intr_assert(MMCHS_SD_STAT_CC);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,10 +523,11 @@ card_identification()
|
||||||
int
|
int
|
||||||
card_query_voltage_and_type(struct sd_card_regs *card)
|
card_query_voltage_and_type(struct sd_card_regs *card)
|
||||||
{
|
{
|
||||||
|
spin_t spin;
|
||||||
command.cmd = MMC_APP_CMD;
|
command.cmd = MMC_APP_CMD;
|
||||||
command.resp_type = RESP_LEN_48;
|
command.resp_type = RESP_LEN_48;
|
||||||
command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */
|
command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */
|
||||||
|
|
||||||
if (mmc_send_cmd(&command)) {
|
if (mmc_send_cmd(&command)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -405,6 +546,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* @todo wait for max 1 ms */
|
/* @todo wait for max 1 ms */
|
||||||
|
spin_init(&spin, SANE_TIMEOUT);
|
||||||
while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
|
while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
|
||||||
command.cmd = MMC_APP_CMD;
|
command.cmd = MMC_APP_CMD;
|
||||||
command.resp_type = RESP_LEN_48;
|
command.resp_type = RESP_LEN_48;
|
||||||
|
@ -432,6 +574,10 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
||||||
if ((command.resp[0] & MMC_OCR_MEM_READY)) {
|
if ((command.resp[0] & MMC_OCR_MEM_READY)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (spin_check(&spin) == FALSE) {
|
||||||
|
mmc_log_warn(&log,
|
||||||
|
"TIMEOUT waiting for the SD card\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
card->ocr = command.resp[3];
|
card->ocr = command.resp[3];
|
||||||
|
@ -536,15 +682,18 @@ read_single_block(struct sd_card_regs *card,
|
||||||
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
||||||
| MMCHS_SD_CMD_DDIR_READ /* read data from card */
|
| MMCHS_SD_CMD_DDIR_READ /* read data from card */
|
||||||
, blknr)) {
|
, blknr)) {
|
||||||
|
mmc_log_warn(&log, "Error sending command\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((read32(base_address + MMCHS_SD_STAT)
|
if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) {
|
||||||
& MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) {
|
intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE);
|
||||||
count++;
|
mmc_log_warn(&log, "Timeout waiting for interrupt\n");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
|
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
|
||||||
|
mmc_log_warn(&log, "Problem BRE should be true\n");
|
||||||
return 1; /* We are not allowed to read data from the
|
return 1; /* We are not allowed to read data from the
|
||||||
* data buffer */
|
* data buffer */
|
||||||
}
|
}
|
||||||
|
@ -558,11 +707,12 @@ read_single_block(struct sd_card_regs *card,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for TC */
|
/* Wait for TC */
|
||||||
while ((read32(base_address +
|
if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) {
|
||||||
MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
|
intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE);
|
||||||
== 0) {
|
mmc_log_warn(&log, "Timeout waiting for interrupt\n");
|
||||||
count++;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||||
|
|
||||||
/* clear and disable the bbr interrupt */
|
/* clear and disable the bbr interrupt */
|
||||||
|
@ -579,17 +729,21 @@ write_single_block(struct sd_card_regs *card,
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
|
||||||
count = 0;
|
if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
|
||||||
|
mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n",
|
||||||
|
__FUNCTION__, read32(base_address + MMCHS_SD_STAT));
|
||||||
|
write32(base_address + MMCHS_SD_STAT,
|
||||||
|
MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
||||||
|
// return 1;
|
||||||
|
}
|
||||||
|
|
||||||
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
||||||
MMCHS_SD_IE_BWR_ENABLE_ENABLE);
|
MMCHS_SD_IE_BWR_ENABLE_ENABLE);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
// set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
|
// set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
|
||||||
set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
|
set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
|
||||||
|
|
||||||
/* Set timeout */
|
|
||||||
set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
|
|
||||||
MMCHS_SD_SYSCTL_DTO_2POW27);
|
|
||||||
|
|
||||||
/* write single block */
|
/* write single block */
|
||||||
if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
|
if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
|
||||||
| MMCHS_SD_CMD_DP_DATA /* Command with data transfer */
|
| MMCHS_SD_CMD_DP_DATA /* Command with data transfer */
|
||||||
|
@ -597,19 +751,32 @@ write_single_block(struct sd_card_regs *card,
|
||||||
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
| MMCHS_SD_CMD_MSBS_SINGLE /* single block */
|
||||||
| MMCHS_SD_CMD_DDIR_WRITE /* write to the card */
|
| MMCHS_SD_CMD_DDIR_WRITE /* write to the card */
|
||||||
, blknr)) {
|
, blknr)) {
|
||||||
|
mmc_log_warn(&log, "Write single block command failed\n");
|
||||||
|
mmc_log_trace(&log, "STAT=(0x%08x)\n",
|
||||||
|
read32(base_address + MMCHS_SD_STAT));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
|
/* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
|
||||||
while ((read32(base_address +
|
if (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) {
|
||||||
MMCHS_SD_STAT) & MMCHS_SD_IE_BWR_ENABLE) == 0) {
|
intr_assert(MMCHS_SD_IE_BWR_ENABLE);
|
||||||
count++;
|
mmc_log_warn(&log, "WFI failed\n");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* clear the interrupt directly */
|
||||||
|
intr_assert(MMCHS_SD_IE_BWR_ENABLE);
|
||||||
|
|
||||||
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
|
if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
|
||||||
|
mmc_log_warn(&log,
|
||||||
|
"Error expected Buffer to be write enabled\n");
|
||||||
return 1; /* not ready to write data */
|
return 1; /* not ready to write data */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (count = 0; count < 512; count += 4) {
|
for (count = 0; count < 512; count += 4) {
|
||||||
|
while (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)){
|
||||||
|
mmc_log_trace(&log, "Error expected Buffer to be write enabled(%d)\n", count);
|
||||||
|
}
|
||||||
*((char *) &value) = buf[count];
|
*((char *) &value) = buf[count];
|
||||||
*((char *) &value + 1) = buf[count + 1];
|
*((char *) &value + 1) = buf[count + 1];
|
||||||
*((char *) &value + 2) = buf[count + 2];
|
*((char *) &value + 2) = buf[count + 2];
|
||||||
|
@ -617,17 +784,14 @@ write_single_block(struct sd_card_regs *card,
|
||||||
write32(base_address + MMCHS_SD_DATA, value);
|
write32(base_address + MMCHS_SD_DATA, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wait for TC */
|
/* Wait for TC */
|
||||||
while ((read32(base_address +
|
if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
||||||
MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
|
intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||||
== 0) {
|
mmc_log_warn(&log, "(Write) Timeout waiting for transfer complete\n");
|
||||||
count++;
|
return 1;
|
||||||
}
|
}
|
||||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
|
||||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR); /* finished.
|
|
||||||
*/
|
|
||||||
/* clear the bwr interrupt FIXME is this right when writing? */
|
|
||||||
write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BWR_ENABLE_CLEAR);
|
|
||||||
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
|
||||||
MMCHS_SD_IE_BWR_ENABLE_DISABLE);
|
MMCHS_SD_IE_BWR_ENABLE_DISABLE);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -661,7 +825,7 @@ mmchs_host_set_instance(struct mmc_host *host, int instance)
|
||||||
int
|
int
|
||||||
mmchs_host_reset(struct mmc_host *host)
|
mmchs_host_reset(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
mmchs_init(1);
|
// mmchs_init(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,7 +839,7 @@ mmchs_card_detect(struct sd_slot *slot)
|
||||||
struct sd_card *
|
struct sd_card *
|
||||||
mmchs_card_initialize(struct sd_slot *slot)
|
mmchs_card_initialize(struct sd_slot *slot)
|
||||||
{
|
{
|
||||||
mmchs_init(1);
|
// mmchs_init(1);
|
||||||
|
|
||||||
struct sd_card *card;
|
struct sd_card *card;
|
||||||
card = &slot->card;
|
card = &slot->card;
|
||||||
|
@ -785,6 +949,7 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
|
||||||
host->card_detect = mmchs_card_detect;
|
host->card_detect = mmchs_card_detect;
|
||||||
host->card_initialize = mmchs_card_initialize;
|
host->card_initialize = mmchs_card_initialize;
|
||||||
host->card_release = mmchs_card_release;
|
host->card_release = mmchs_card_release;
|
||||||
|
host->hw_intr = mmchs_hw_intr;
|
||||||
host->read = mmchs_host_read;
|
host->read = mmchs_host_read;
|
||||||
host->write = mmchs_host_write;
|
host->write = mmchs_host_write;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define MMCHS_SD_SYSCTL 0x22c /* SD System control (reset,clocks and timeout) */
|
#define MMCHS_SD_SYSCTL 0x22c /* SD System control (reset,clocks and timeout) */
|
||||||
#define MMCHS_SD_STAT 0x230 /* SD Interrupt status */
|
#define MMCHS_SD_STAT 0x230 /* SD Interrupt status */
|
||||||
#define MMCHS_SD_IE 0x234 /* SD Interrupt Enable register */
|
#define MMCHS_SD_IE 0x234 /* SD Interrupt Enable register */
|
||||||
|
#define MMCHS_SD_ISE 0x238 /* SD Interrupt Signal Enable register */
|
||||||
#define MMCHS_SD_CAPA 0x240 /* Capabilities of the host controller */
|
#define MMCHS_SD_CAPA 0x240 /* Capabilities of the host controller */
|
||||||
#define MMCHS_SD_CUR_CAPA 0x248 /* Current capabilities of the host controller */
|
#define MMCHS_SD_CUR_CAPA 0x248 /* Current capabilities of the host controller */
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@
|
||||||
#define MMCHS_SD_SYSCTL_DTO (0xf << 16) /* Data timeout counter */
|
#define MMCHS_SD_SYSCTL_DTO (0xf << 16) /* Data timeout counter */
|
||||||
#define MMCHS_SD_SYSCTL_DTO_2POW13 (0x0 << 16) /* TCF x 2^13 */
|
#define MMCHS_SD_SYSCTL_DTO_2POW13 (0x0 << 16) /* TCF x 2^13 */
|
||||||
#define MMCHS_SD_SYSCTL_DTO_2POW14 (0x1 << 16) /* TCF x 2^14 */
|
#define MMCHS_SD_SYSCTL_DTO_2POW14 (0x1 << 16) /* TCF x 2^14 */
|
||||||
#define MMCHS_SD_SYSCTL_DTO_2POW27 (0x3 << 16) /* TCF x 2^27 */
|
#define MMCHS_SD_SYSCTL_DTO_2POW27 (0xe << 16) /* TCF x 2^27 */
|
||||||
|
|
||||||
#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */
|
#define MMCHS_SD_STAT_ERRI (0x01 << 15) /* Error interrupt */
|
||||||
#define MMCHS_SD_STAT_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28)
|
#define MMCHS_SD_STAT_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28)
|
||||||
|
|
|
@ -549,6 +549,9 @@ service mmc
|
||||||
{
|
{
|
||||||
system
|
system
|
||||||
PRIVCTL # 4
|
PRIVCTL # 4
|
||||||
|
IRQCTL # 19
|
||||||
|
;
|
||||||
|
irq 83; # IRQ 83 allowed
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue