diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index efca6b02e..9480ecf2c 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -1,6 +1,6 @@ # Makefile for the mmc driver. PROG= mmc -SRCS= mmcblk.c mmchost_dummy.c mmclog.h sdhcreg.h sdmmcreg.h +SRCS= mmcblk.c mmchost_dummy.c sdhcreg.h sdmmcreg.h .if ${MACHINE_ARCH} == "earm" diff --git a/drivers/mmc/README.txt b/drivers/mmc/README.txt index cd353ed95..241934f18 100644 --- a/drivers/mmc/README.txt +++ b/drivers/mmc/README.txt @@ -27,13 +27,8 @@ The SD protocol is well defined and the imported the netbsd sdhcreg and sdmmcreg headers will allow us to make the MMC interface more generic. We would like mmchost_mmchs to be split in a generic part and a specific part. -* Using interrupts -At time of writing the interrupt handlers on the ARM port are not implemented. -Once that is done we will be able to rewrite the code to use proper interrupt -handlers. - -* 4 and 8 bits access -The driver currently only reads data over a single data line. Adding support +* 8 bits access +The driver currently only reads data over 1 or 4 bits address lines. Adding support for 4 or 8 bits(for movinands) mode is very welcome. * DMA. diff --git a/drivers/mmc/mmcblk.c b/drivers/mmc/mmcblk.c index 4720a9826..7541a0605 100644 --- a/drivers/mmc/mmcblk.c +++ b/drivers/mmc/mmcblk.c @@ -6,6 +6,7 @@ #include #include #include +#include #include /* system headers */ @@ -20,10 +21,9 @@ /* local headers */ #include "mmchost.h" -#include "mmclog.h" /* used for logging */ -static struct mmclog log = { +static struct log log = { .name = "mmc_block", .log_level = LEVEL_INFO, .log_func = default_log @@ -62,8 +62,7 @@ static void block_signal_handler_cb(int signo); void bdr_alarm(clock_t stamp) { - mmc_log_debug(&log, "alarm %d\n", stamp); - + log_debug(&log, "alarm %d\n", stamp); } static int apply_env(); @@ -91,7 +90,7 @@ static struct blockdriver mmc_driver = { static void hw_intr(unsigned int irqs) { - mmc_log_debug(&log, "Hardware inter left over\n"); + log_debug(&log, "Hardware inter left over\n"); host.hw_intr(irqs); } @@ -118,7 +117,7 @@ apply_env() } else if (strncmp(driver, "dummy", strlen("dummy") + 1) == 0) { host_initialize_host_structure_dummy(&host); } else { - mmc_log_warn(&log, "Unknown driver %s\n", driver); + log_warn(&log, "Unknown driver %s\n", driver); } /* Initialize the verbosity level. */ v = 0; @@ -131,7 +130,7 @@ apply_env() v = 0; env_parse("instance", "d", 0, &v, 0, 3); if (host.host_set_instance(&host, v)) { - mmc_log_warn(&log, "Failed to set mmc instance to %d\n", v); + log_warn(&log, "Failed to set mmc instance to %d\n", v); return -1; /* NOT OK */ } return OK; @@ -153,15 +152,14 @@ block_open(dev_t minor, int access) i = j = part_count = sub_part_count = 0; if (!slot) { - mmc_log_debug(&log, - "Not handling open on non existing slot\n"); + log_debug(&log, "Not handling open on non existing slot\n"); return EIO; } assert(slot->host != NULL); if (!slot->host->card_detect(slot)) { - mmc_log_debug(&log, "No card inserted in the SD slot\n"); + log_debug(&log, "No card inserted in the SD slot\n"); return EIO; } @@ -169,14 +167,14 @@ block_open(dev_t minor, int access) if (slot->card.state == SD_MODE_DATA_TRANSFER_MODE) { assert(slot->card.open_ct >= 0); slot->card.open_ct++; - mmc_log_trace(&log, "increased open count to %d\n", + log_trace(&log, "increased open count to %d\n", slot->card.open_ct); return OK; } /* We did not have an sd-card inserted so we are going to probe for it */ - mmc_log_debug(&log, "First open on (%d)\n", minor); + log_debug(&log, "First open on (%d)\n", minor); if (!host.card_initialize(slot)) { // * TODO: set card state to INVALID until removed? */ return EIO; @@ -185,27 +183,27 @@ block_open(dev_t minor, int access) partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY, 0 /* atapi device?? */ ); - mmc_log_trace(&log, "descr \toffset(bytes) size(bytes)\n", minor); + log_trace(&log, "descr \toffset(bytes) size(bytes)\n", minor); - mmc_log_trace(&log, "disk %d\t0x%016llx 0x%016llx\n", i, + log_trace(&log, "disk %d\t0x%016llx 0x%016llx\n", i, slot->card.part[0].dv_base, slot->card.part[0].dv_size); for (i = 1; i < 5; i++) { if (slot->card.part[i].dv_size == 0) continue; part_count++; - mmc_log_trace(&log, "part %d\t0x%016llx 0x%016llx\n", i, + log_trace(&log, "part %d\t0x%016llx 0x%016llx\n", i, slot->card.part[i].dv_base, slot->card.part[i].dv_size); for (j = 0; j < 4; j++) { if (slot->card.subpart[(i - 1) * 4 + j].dv_size == 0) continue; sub_part_count++; - mmc_log_trace(&log, + log_trace(&log, " 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_size); } } - mmc_log_debug(&log, "Found %d partitions and %d sub partitions\n", + log_debug(&log, "Found %d partitions and %d sub partitions\n", part_count, sub_part_count); slot->card.open_ct++; assert(slot->card.open_ct == 1); @@ -222,8 +220,7 @@ block_close(dev_t minor) slot = get_slot(minor); if (!slot) { - mmc_log_debug(&log, - "Not handling open on non existing slot\n"); + log_debug(&log, "Not handling open on non existing slot\n"); return EIO; } @@ -236,14 +233,13 @@ block_close(dev_t minor) * return */ if (slot->card.open_ct > 1) { slot->card.open_ct--; - mmc_log_trace(&log, "decreased open count to %d\n", + log_trace(&log, "decreased open count to %d\n", slot->card.open_ct); return OK; } assert(slot->card.open_ct == 1); - mmc_log_debug(&log, - "freeing the block device as it is no longer used\n"); + log_debug(&log, "freeing the block device as it is no longer used\n"); /* release the card as check the open_ct should be 0 */ slot->host->card_release(&slot->card); @@ -307,23 +303,23 @@ block_transfer(dev_t minor, /* minor device number */ /* Get the current "device" geometry */ dev = block_part(minor); if (dev == NULL) { - mmc_log_warn(&log, + log_warn(&log, "Transfer requested on unknown device minor(%d)\n", minor); /* Unknown device */ return ENXIO; } - mmc_log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor, + log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor, (do_write) ? "Write" : "Read", position); slot = get_slot(minor); assert(slot); if (slot->card.blk_size == 0) { - mmc_log_warn(&log, "Request on a card with block size of 0\n"); + log_warn(&log, "Request on a card with block size of 0\n"); return EINVAL; } if (slot->card.blk_size > COPYBUFF_SIZE) { - mmc_log_warn(&log, + log_warn(&log, "Card block size (%d) exceeds internal buffer size %d\n", slot->card.blk_size, COPYBUFF_SIZE); return EINVAL; @@ -333,7 +329,7 @@ block_transfer(dev_t minor, /* minor device number */ * parameters of transfers, in those cases we return EINVAL */ if (position % slot->card.blk_size != 0) { /* Starting at a block boundary */ - mmc_log_warn(&log, + log_warn(&log, "Requests must start at a block boundary" "(start,block size)=(%016llx,%08x)\n", position, slot->card.blk_size); @@ -346,7 +342,7 @@ block_transfer(dev_t minor, /* minor device number */ /* Are we trying to start reading past the end */ if (position >= dev->dv_size) { - mmc_log_warn(&log, "start reading past drive size\n"); + log_warn(&log, "start reading past drive size\n"); return 0; }; @@ -356,7 +352,7 @@ block_transfer(dev_t minor, /* minor device number */ assert(ciov != NULL); if (ciov->iov_size % blk_size != 0) { /* transfer a multiple of blk_size */ - mmc_log_warn(&log, + log_warn(&log, "Requests must start at a block boundary " "(start,block size)=(%016llx,%08x)\n", position, slot->card.blk_size); @@ -364,7 +360,7 @@ block_transfer(dev_t minor, /* minor device number */ } if (ciov->iov_size <= 0) { - mmc_log_warn(&log, + log_warn(&log, "Invalid iov size for iov %d of %d size\n", counter, nr_req, ciov->iov_size); return EINVAL; @@ -385,7 +381,7 @@ block_transfer(dev_t minor, /* minor device number */ io_size = dev->dv_size - (position + bytes_written); }; - mmc_log_trace(&log, + log_trace(&log, "I/O %s request(%d/%d) iov(grant,size,iosize," "offset)=(%d,%d,%d,%d)\n", (do_write) ? "write" : "read", counter + 1, nr_req, @@ -400,7 +396,7 @@ block_transfer(dev_t minor, /* minor device number */ i * blk_size, (vir_bytes) copybuff, blk_size); if (r != OK) { - mmc_log_warn(&log, + log_warn(&log, "I/O write error: %s iov(base,size)=(%d,%d)" " at offset=%d\n", strerror(_SIGN r), ciov->iov_addr, @@ -424,7 +420,7 @@ block_transfer(dev_t minor, /* minor device number */ r = copyto(endpt, ciov->iov_addr, i * blk_size, (vir_bytes) copybuff, blk_size); if (r != OK) { - mmc_log_warn(&log, + log_warn(&log, "I/O read error: %s iov(base,size)=(%d,%d)" " at offset=%d\n", strerror(_SIGN r), ciov->iov_addr, @@ -448,13 +444,13 @@ block_ioctl(dev_t minor, { /* IOCTL handling */ struct sd_slot *slot; - mmc_log_trace(&log, + log_trace(&log, "enter (minor,request,endpoint,grant)=(%d,%lu,%d)\n", minor, request, endpt, grant); slot = get_slot(minor); if (!slot) { - mmc_log_warn(&log, + log_warn(&log, "Doing ioctl on non existing block device(%d)\n", minor); return EINVAL; } @@ -462,7 +458,7 @@ block_ioctl(dev_t minor, switch (request) { case DIOCOPENCT: // TODO: add a check for card validity */ - mmc_log_trace(&log, "returning open count %d\n", + log_trace(&log, "returning open count %d\n", slot->card.open_ct); /* return the current open count */ return sys_safecopyto(endpt, grant, 0, @@ -496,14 +492,14 @@ block_part(dev_t minor) dev = NULL; slot = get_slot(minor); if (!slot) { - mmc_log_warn(&log, + log_warn(&log, "Device information requested for non existing partition " "minor(%d)\n", minor); return NULL; } if (!slot->host->card_detect(slot)) { - mmc_log_warn(&log, + log_warn(&log, "Device information requested from empty slot(%d)\n", minor); return NULL; @@ -512,19 +508,19 @@ block_part(dev_t minor) if (minor < 5) { /* we are talking about the first disk */ dev = &slot->card.part[minor]; - mmc_log_trace(&log, + log_trace(&log, "returning partition(%d) (base,size)=(0x%016llx,0x%016llx)\n", minor, dev->dv_base, dev->dv_size); } else if (minor >= 128 && minor < 128 + 16) { /* sub partitions of the first disk we don't care about the * rest */ dev = &slot->card.subpart[minor - 128]; - mmc_log_trace(&log, + log_trace(&log, "returning sub partition(%d) (base,size)=(0x%016llx,0x%016llx)\n", minor - 128, dev->dv_base, dev->dv_size); } else { - mmc_log_warn(&log, + log_warn(&log, "Device information requested for non existing " "partition minor(%d)\n", minor); } @@ -537,16 +533,14 @@ block_part(dev_t minor) static void sef_local_startup() { - mmc_log_info(&log, "Initializing the MMC block device\n"); + log_info(&log, "Initializing the MMC block device\n"); if (apply_env()) { - mmc_log_warn(&log, - "Failed while applying environment settings\n"); + log_warn(&log, "Failed while applying environment settings\n"); exit(EXIT_FAILURE); } if (host.host_init(&host)) { - mmc_log_warn(&log, - "Failed to initialize the host controller\n"); + log_warn(&log, "Failed to initialize the host controller\n"); exit(EXIT_FAILURE); } /* @@ -574,16 +568,16 @@ block_system_event_cb(int type, sef_init_info_t * info) * sef_local_startup */ switch (type) { case SEF_INIT_FRESH: - mmc_log_info(&log, "System event framework fresh start\n"); + log_info(&log, "System event framework fresh start\n"); break; case SEF_INIT_LU: /* Restore the state. post update */ - mmc_log_info(&log, "System event framework live update\n"); + log_info(&log, "System event framework live update\n"); break; case SEF_INIT_RESTART: - mmc_log_info(&log, "System event framework post restart\n"); + log_info(&log, "System event framework post restart\n"); break; } blockdriver_announce(type); @@ -598,7 +592,7 @@ block_signal_handler_cb(int signo) { struct sd_slot *slot; - mmc_log_debug(&log, "System event framework signal handler sig(%d)\n", + log_debug(&log, "System event framework signal handler sig(%d)\n", signo); /* Only check for termination signal, ignore anything else. */ if (signo != SIGTERM) @@ -609,12 +603,12 @@ block_signal_handler_cb(int signo) slot = get_slot(0); assert(slot); if (slot->card.open_ct > 0) { - mmc_log_debug(&log, "Not responding to SIGTERM (open count=%d)\n", + log_debug(&log, "Not responding to SIGTERM (open count=%d)\n", slot->card.open_ct); return; } - mmc_log_info(&log, "MMC driver exit"); + log_info(&log, "MMC driver exit"); exit(0); } @@ -642,7 +636,7 @@ get_slot(dev_t minor) /* a minor from the first disk */ return &host.slot[0]; } else { - mmc_log_trace(&log, + log_trace(&log, "Device information requested for non existing partition " "minor(%d)\n", minor); return NULL; @@ -655,7 +649,7 @@ set_log_level(int level) if (level < 0 || level >= 4) { return; } - mmc_log_info(&log, "Setting verbosity level to %d\n", level); + log_info(&log, "Setting verbosity level to %d\n", level); log.log_level = level; if (host.set_log_level) { host.set_log_level(level); diff --git a/drivers/mmc/mmchost_dummy.c b/drivers/mmc/mmchost_dummy.c index 15a741284..db26a6af3 100644 --- a/drivers/mmc/mmchost_dummy.c +++ b/drivers/mmc/mmchost_dummy.c @@ -1,6 +1,7 @@ /* kernel headers */ #include #include +#include /* usr headers */ #include @@ -10,14 +11,13 @@ #include /* local headers */ -#include "mmclog.h" #include "mmchost.h" #include "sdmmcreg.h" /* * Define a structure to be used for logging */ -static struct mmclog log = { +static struct log log = { .name = "mmc_host_memory", .log_level = LEVEL_INFO, .log_func = default_log @@ -36,7 +36,7 @@ init_dummy_sdcard(struct sd_slot *slot) assert(slot != NULL); - mmc_log_info(&log, "Using a dummy card \n"); + 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) { @@ -81,7 +81,7 @@ dummy_set_log_level(int level) int dummy_host_set_instance(struct mmc_host *host, int instance) { - mmc_log_info(&log, "Using instance number %d\n", instance); + log_info(&log, "Using instance number %d\n", instance); if (instance != 0) { return EIO; } diff --git a/drivers/mmc/mmchost_mmchs.c b/drivers/mmc/mmchost_mmchs.c index 58390ef72..801b84ecb 100644 --- a/drivers/mmc/mmchost_mmchs.c +++ b/drivers/mmc/mmchost_mmchs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include /* local headers */ -#include "mmclog.h" #include "mmchost.h" /* header imported from netbsd */ @@ -41,12 +41,12 @@ static int hook_id = 1; #endif #endif -#define SANE_TIMEOUT 500000 /* 500 MS */ +#define SANE_TIMEOUT 500000 /* 500 ms */ /* * Define a structure to be used for logging */ -static struct mmclog log = { +static struct log log = { .name = "mmc_host_mmchs", .log_level = LEVEL_INFO, .log_func = default_log @@ -98,7 +98,7 @@ mmchs_init(uint32_t instance) while (!(read32(base_address + MMCHS_SD_SYSSTATUS) & MMCHS_SD_SYSSTATUS_RESETDONE)) { if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, "mmc init timeout\n"); + log_warn(&log, "mmc init timeout\n"); return 1; } } @@ -159,7 +159,7 @@ mmchs_init(uint32_t instance) while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP) != MMCHS_SD_HCTL_SDBP_ON) { if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, "mmc init timeout SDBP not set\n"); + log_warn(&log, "mmc init timeout SDBP not set\n"); return 1; } } @@ -181,9 +181,8 @@ mmchs_init(uint32_t instance) spin_init(&spin, SANE_TIMEOUT); while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS) != MMCHS_SD_SYSCTL_ICS_STABLE) { - if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, "clock not stable\n"); + log_warn(&log, "clock not stable\n"); return 1; } } @@ -200,9 +199,7 @@ mmchs_init(uint32_t instance) MMCHS_SD_IE_TC_ENABLE_ENABLE); /* enable error interrupts */ - /* NOTE: We are currently skipping the BADA interrupt it does get - * raised for unknown reasons */ - set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0x0fffffffu); + set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0xffffffffu); /* clear the error interrupts */ set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK, @@ -219,15 +216,14 @@ mmchs_init(uint32_t instance) while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC) != MMCHS_SD_STAT_CC_RAISED) { if (read32(base_address + MMCHS_SD_STAT) & 0x8000) { - mmc_log_warn(&log, "%s, error stat %x\n", + log_warn(&log, "%s, error stat %x\n", __FUNCTION__, read32(base_address + MMCHS_SD_STAT)); return 1; } if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, - "Interrupt not raised during init\n"); + log_warn(&log, "Interrupt not raised during init\n"); return 1; } } @@ -261,10 +257,86 @@ mmchs_init(uint32_t instance) return 0; } +void +intr_deassert(int mask) +{ + if (read32(base_address + MMCHS_SD_STAT) & 0x8000) { + 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); + } else { + write32(base_address + MMCHS_SD_STAT, mask); + } +} + +/* pointer to the data to transfer used in bwr and brr */ +unsigned char *io_data; +int io_len; + +void +handle_bwr() +{ + /* handle buffer write ready interrupts. These happen in a non + * predictable way (eg. we send a request but don't know if we are + * first doing to get a request completed before we are allowed to + * send the data to the harware or not */ + uint32_t value; + uint32_t count; + assert(read32(base_address + + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN); + assert(io_data != NULL); + + for (count = 0; count < io_len; count += 4) { + while (!(read32(base_address + + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) { + log_warn(&log, + "Error expected Buffer to be write enabled(%d)\n", + count); + } + *((char *) &value) = io_data[count]; + *((char *) &value + 1) = io_data[count + 1]; + *((char *) &value + 2) = io_data[count + 2]; + *((char *) &value + 3) = io_data[count + 3]; + write32(base_address + MMCHS_SD_DATA, value); + } + intr_deassert(MMCHS_SD_IE_BWR_ENABLE); + /* expect buffer to be write enabled */ + io_data = NULL; +} + +void +handle_brr() +{ + /* handle buffer read ready interrupts. genrally these happen afther + * the data is read from the sd card. */ + + uint32_t value; + uint32_t count; + + /* Problem BRE should be true */ + assert(read32(base_address + + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN); + + assert(io_data != NULL); + + for (count = 0; count < io_len; count += 4) { + value = read32(base_address + MMCHS_SD_DATA); + io_data[count] = *((char *) &value); + io_data[count + 1] = *((char *) &value + 1); + io_data[count + 2] = *((char *) &value + 2); + io_data[count + 3] = *((char *) &value + 3); + } + /* clear bbr interrupt */ + intr_deassert(MMCHS_SD_IE_BRR_ENABLE_ENABLE); + io_data = NULL; +} + static void mmchs_hw_intr(unsigned int irqs) { - mmc_log_warn(&log, "Hardware interrupt left over\n"); + log_warn(&log, "Hardware interrupt left over (0x%08lx)\n", + read32(base_address + MMCHS_SD_STAT)); #ifdef USE_INTR if (sys_irqenable(&hook_id) != OK) @@ -300,27 +372,47 @@ intr_wait(int mask) switch (_ENDPOINT_P(m.m_source)) { case CLOCK: /* Timeout. */ - // w_timeout(); /* a.o. set w_status */ - mmc_log_warn(&log, "TIMEOUT\n"); + 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, + while ((v = + read32(base_address + + MMCHS_SD_STAT)) != 0) { + if (v & MMCHS_SD_IE_BWR_ENABLE) { + handle_bwr(); + continue; + } + if (v & MMCHS_SD_IE_BRR_ENABLE) { + handle_brr(); + continue; + } + + if (v & mask) { + /* this is the normal return + * path, the mask given + * matches the pending + * interrupt. canel the alarm + * and return */ + sys_setalarm(0, 0); + return 0; + } else if (v & (1 << 15)) { + return 1; /* error */ + } + + log_warn(&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; } + /* if we end up here re-enable interrupts for + * the next round */ + if (sys_irqenable(&hook_id) != OK) + printf + ("Failed to re-enable irqenable irq\n"); + break; default: /* * unhandled message. queue it and @@ -329,7 +421,6 @@ intr_wait(int mask) blockdriver_mq_queue(&m, ipc_status); } } else { - mmc_log_debug(&log, "Other\n"); /* * unhandled message. queue it and handle it in the * blockdriver loop. @@ -348,15 +439,23 @@ intr_wait(int mask) counter++; v = read32(base_address + MMCHS_SD_STAT); if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, + log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n", counter, v, mask); return 1; } + if (v & MMCHS_SD_IE_BWR_ENABLE) { + handle_bwr(); + continue; + } + if (v & MMCHS_SD_IE_BRR_ENABLE) { + handle_brr(); + continue; + } if (v & mask) { return 0; } else if (v & 0xFF00) { - mmc_log_debug(&log, + log_debug(&log, "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", v, mask); return 1; @@ -366,36 +465,26 @@ intr_wait(int mask) #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 mmchs_send_cmd(uint32_t command, uint32_t arg) { /* Read current interrupt status and fail it an interrupt is already * asserted */ + assert(read32(base_address + MMCHS_SD_STAT) == 0); /* Set arguments */ write32(base_address + MMCHS_SD_ARG, arg); /* Set command */ set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command); - if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) { - intr_assert(MMCHS_SD_STAT_CC); - mmc_log_warn(&log, "Failure waiting for interrupt\n"); + if (intr_wait(MMCHS_SD_STAT_CC)) { + uint32_t v = read32(base_address + MMCHS_SD_STAT); + intr_deassert(MMCHS_SD_STAT_CC); + log_warn(&log, "Failure waiting for interrupt 0x%lx\n", v); return 1; } + intr_deassert(MMCHS_SD_STAT_CC); if ((command & MMCHS_SD_CMD_RSP_TYPE) == MMCHS_SD_CMD_RSP_TYPE_48B_BUSY) { @@ -404,18 +493,10 @@ mmchs_send_cmd(uint32_t command, uint32_t arg) */ if ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) { - mmc_log_warn(&log, "TC should be raised\n"); - } - write32(base_address + MMCHS_SD_STAT, - MMCHS_SD_IE_TC_ENABLE_CLEAR); - - if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) { - intr_assert(MMCHS_SD_STAT_CC); - mmc_log_warn(&log, "Failure waiting for clear\n"); - return 1; + log_warn(&log, "TC should be raised\n"); } + intr_deassert(MMCHS_SD_STAT_TC); } - intr_assert(MMCHS_SD_STAT_CC); return 0; } @@ -426,8 +507,6 @@ mmc_send_cmd(struct mmc_command *c) /* convert the command to a hsmmc command */ int ret; uint32_t cmd, arg; - uint32_t count; - uint32_t value; cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd); arg = c->args; @@ -449,11 +528,10 @@ mmc_send_cmd(struct mmc_command *c) } /* read single block */ - if (c->cmd == MMC_READ_BLOCK_SINGLE) { + if ((c->cmd == MMC_READ_BLOCK_SINGLE) || (c->cmd == SD_APP_SEND_SCR)) { cmd |= MMCHS_SD_CMD_DP_DATA; /* Command with data transfer */ cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */ cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */ - } /* write single block */ @@ -465,7 +543,7 @@ mmc_send_cmd(struct mmc_command *c) /* check we are in a sane state */ if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) { - mmc_log_warn(&log, "%s, interrupt already raised stat %08x\n", + 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); @@ -483,12 +561,50 @@ mmc_send_cmd(struct mmc_command *c) MMCHS_SD_IE_BWR_ENABLE, MMCHS_SD_IE_BWR_ENABLE_ENABLE); } + io_data = c->data; + io_len = c->data_len; + assert(io_len <= 0xFFF); /* only 12 bits */ + assert(io_data != NULL); + set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, io_len); } - set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512); - ret = mmchs_send_cmd(cmd, arg); + if (cmd & MMCHS_SD_CMD_DP_DATA) { + assert(c->data_len); + if (cmd & MMCHS_SD_CMD_DDIR_READ) { + /* Wait for TC */ + if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { + intr_deassert(MMCHS_SD_IE_TC_ENABLE_ENABLE); + log_warn(&log, + "(Read) Timeout waiting for interrupt\n"); + return 1; + } + + write32(base_address + MMCHS_SD_STAT, + MMCHS_SD_IE_TC_ENABLE_CLEAR); + + /* disable the bbr interrupt */ + set32(base_address + MMCHS_SD_IE, + MMCHS_SD_IE_BRR_ENABLE, + MMCHS_SD_IE_BRR_ENABLE_DISABLE); + } else { + /* Wait for TC */ + if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { + intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR); + log_warn(&log, + "(Write) Timeout waiting for transfer complete\n"); + return 1; + } + intr_deassert(MMCHS_SD_IE_TC_ENABLE_CLEAR); + + set32(base_address + MMCHS_SD_IE, + MMCHS_SD_IE_BWR_ENABLE, + MMCHS_SD_IE_BWR_ENABLE_DISABLE); + + } + } + /* copy response into cmd->resp */ switch (c->resp_type) { case RESP_LEN_48_CHK_BUSY: @@ -507,98 +623,6 @@ mmc_send_cmd(struct mmc_command *c) return 1; } - if (cmd & MMCHS_SD_CMD_DP_DATA) { - count = 0; - assert(c->data_len); - if (cmd & MMCHS_SD_CMD_DDIR_READ) { - if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) { - intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE); - mmc_log_warn(&log, - "Timeout waiting for interrupt\n"); - return 1; - } - - 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 data buffer */ - } - - for (count = 0; count < c->data_len; count += 4) { - value = read32(base_address + MMCHS_SD_DATA); - c->data[count] = *((char *) &value); - c->data[count + 1] = *((char *) &value + 1); - c->data[count + 2] = *((char *) &value + 2); - c->data[count + 3] = *((char *) &value + 3); - } - - /* Wait for TC */ - if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) { - intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE); - mmc_log_warn(&log, - "Timeout waiting for interrupt\n"); - return 1; - } - - write32(base_address + MMCHS_SD_STAT, - MMCHS_SD_IE_TC_ENABLE_CLEAR); - - /* clear and disable the bbr interrupt */ - write32(base_address + MMCHS_SD_STAT, - MMCHS_SD_IE_BRR_ENABLE_CLEAR); - set32(base_address + MMCHS_SD_IE, - MMCHS_SD_IE_BRR_ENABLE, - MMCHS_SD_IE_BRR_ENABLE_DISABLE); - } else { - /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */ - if (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) { - intr_assert(MMCHS_SD_IE_BWR_ENABLE); - 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)) - { - mmc_log_warn(&log, - "Error expected Buffer to be write enabled\n"); - return 1; /* not ready to write data */ - } - - 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) = c->data[count]; - *((char *) &value + 1) = c->data[count + 1]; - *((char *) &value + 2) = c->data[count + 2]; - *((char *) &value + 3) = c->data[count + 3]; - write32(base_address + MMCHS_SD_DATA, value); - } - - /* Wait for TC */ - if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) { - intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR); - mmc_log_warn(&log, - "(Write) Timeout waiting for transfer complete\n"); - return 1; - } - intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR); - set32(base_address + MMCHS_SD_IE, - MMCHS_SD_IE_BWR_ENABLE, - MMCHS_SD_IE_BWR_ENABLE_DISABLE); - - } - } return ret; } @@ -642,14 +666,13 @@ card_identification() if (mmc_send_cmd(&command)) { /* We currently only support 2.0, and 1.0 won't respond to * this request */ - mmc_log_warn(&log, "%s, non SDHC card inserted\n", - __FUNCTION__); + log_warn(&log, "%s, non SDHC card inserted\n", __FUNCTION__); return 1; } if (!(command.resp[0] == (MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN))) { - mmc_log_warn(&log, "%s, check pattern check failed %08x\n", + log_warn(&log, "%s, check pattern check failed %08x\n", __FUNCTION__, command.resp[0]); return 1; } @@ -661,13 +684,6 @@ card_query_voltage_and_type(struct sd_card_regs *card) { struct mmc_command command; spin_t spin; - command.cmd = MMC_APP_CMD; - command.resp_type = RESP_LEN_48; - command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ - - if (mmc_send_cmd(&command)) { - return 1; - } command.cmd = SD_APP_OP_COND; command.resp_type = RESP_LEN_48; @@ -679,18 +695,12 @@ card_query_voltage_and_type(struct sd_card_regs *card) MMC_OCR_2_7V_2_8V; command.args |= MMC_OCR_HCS; /* RCA=0000 */ - if (mmc_send_cmd(&command)) { + if (mmc_send_app_cmd(card, &command)) { return 1; } /* @todo wait for max 1 ms */ spin_init(&spin, SANE_TIMEOUT); while (!(command.resp[0] & MMC_OCR_MEM_READY)) { - command.cmd = MMC_APP_CMD; - command.resp_type = RESP_LEN_48; - command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ - if (mmc_send_cmd(&command)) { - return 1; - } /* Send ADMD41 */ /* 0x1 << 30 == send HCS (Host capacity support) and get OCR @@ -703,7 +713,7 @@ card_query_voltage_and_type(struct sd_card_regs *card) | MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V; command.args |= MMC_OCR_HCS; /* RCA=0000 */ - if (mmc_send_cmd(&command)) { + if (mmc_send_app_cmd(card, &command)) { return 1; } @@ -712,8 +722,7 @@ card_query_voltage_and_type(struct sd_card_regs *card) break; } if (spin_check(&spin) == FALSE) { - mmc_log_warn(&log, - "TIMEOUT waiting for the SD card\n"); + log_warn(&log, "TIMEOUT waiting for the SD card\n"); } } @@ -777,12 +786,12 @@ card_csd(struct sd_card_regs *card) card->csd[3] = command.resp[3]; if (SD_CSD_CSDVER(card->csd) != SD_CSD_CSDVER_2_0) { - mmc_log_warn(&log, "Version 2.0 of CSD register expected\n"); + log_warn(&log, "Version 2.0 of CSD register expected\n"); return 1; } /* sanity check */ - // mmc_log_warn(&log,"size = %llu bytes\n", (long long + // log_warn(&log,"size = %llu bytes\n", (long long // unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512); return 0; } @@ -801,7 +810,6 @@ select_card(struct sd_card_regs *card) } return 0; } - int read_single_block(struct sd_card_regs *card, uint32_t blknr, unsigned char *buf) @@ -815,7 +823,7 @@ read_single_block(struct sd_card_regs *card, command.data_len = 512; if (mmc_send_cmd(&command)) { - mmc_log_warn(&log, "Error sending command\n"); + log_warn(&log, "Error sending command\n"); return 1; } @@ -828,8 +836,6 @@ write_single_block(struct sd_card_regs *card, { struct mmc_command command; - set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512); - command.cmd = MMC_WRITE_BLOCK_SINGLE; command.args = blknr; command.resp_type = RESP_LEN_48; @@ -838,7 +844,7 @@ write_single_block(struct sd_card_regs *card, /* write single block */ if (mmc_send_cmd(&command)) { - mmc_log_warn(&log, "Write single block command failed\n"); + log_warn(&log, "Write single block command failed\n"); return 1; } @@ -863,7 +869,7 @@ mmchs_set_log_level(int level) int mmchs_host_set_instance(struct mmc_host *host, int instance) { - mmc_log_info(&log, "Using instance number %d\n", instance); + log_info(&log, "Using instance number %d\n", instance); if (instance != 0) { return EIO; } @@ -895,40 +901,38 @@ mmchs_card_initialize(struct sd_slot *slot) card->slot = slot; if (card_goto_idle_state()) { - mmc_log_warn(&log, "Failed to go idle state\n"); + log_warn(&log, "Failed to go idle state\n"); return NULL; } if (card_identification()) { - mmc_log_warn(&log, "Failed to do card_identification\n"); + log_warn(&log, "Failed to do card_identification\n"); return NULL; } if (card_query_voltage_and_type(&slot->card.regs)) { - mmc_log_warn(&log, - "Failed to do card_query_voltage_and_type\n"); + log_warn(&log, "Failed to do card_query_voltage_and_type\n"); return NULL; } if (card_identify(&slot->card.regs)) { - mmc_log_warn(&log, "Failed to identify card\n"); + log_warn(&log, "Failed to identify card\n"); return NULL; } /* We have now initialized the hardware identified the card */ if (card_csd(&slot->card.regs)) { - mmc_log_warn(&log, - "failed to read csd (card specific data)\n"); + log_warn(&log, "failed to read csd (card specific data)\n"); return NULL; } if (select_card(&slot->card.regs)) { - mmc_log_warn(&log, "Failed to select card\n"); + log_warn(&log, "Failed to select card\n"); return NULL; } if (SD_CSD_READ_BL_LEN(slot->card.regs.csd) != 0x09) { /* for CSD version 2.0 the value is fixed to 0x09 and means a * block size of 512 */ - mmc_log_warn(&log, "Block size expect to be 512\n"); + log_warn(&log, "Block size expect to be 512\n"); return NULL; } @@ -981,6 +985,7 @@ mmchs_card_release(struct sd_card *card) card->open_ct--; card->state = SD_MODE_UNINITIALIZED; /* TODO:Set card state */ + return OK; } diff --git a/drivers/mmc/mmclog.h b/drivers/mmc/mmclog.h deleted file mode 100644 index 872823a3e..000000000 --- a/drivers/mmc/mmclog.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef __MMCLOG_H__ -#define __MMCLOG_H__ -/* - * Simple logging functions for the MMC layer - */ - -/* - * LEVEL_NONE do not log anything. - * LEVEL_WARN Information that needs to be known. - * LEVEL_INFO Basic information like startup messages and occasional events. - * LEVEL_DEBUG debug statements about things happening that are less expected. - * LEVEL_TRACE Way to much information for anybody. - */ - -#define LEVEL_NONE 0 -#define LEVEL_WARN 1 -#define LEVEL_INFO 2 -#define LEVEL_DEBUG 3 -#define LEVEL_TRACE 4 - -static const char *level_string[5] = { - "none", - "warn", - "info", - "debug", - "trace" -}; - -/* - * struct to be initialized by the user of the logging system. - * - * name: The name attribute is used in logging statements do differentiate - * drivers - * - * log_level The level attribute describes the requested logging level. a level - * of 1 will only print warnings while a level of 4 will print all the trace - * information. - * - * log_func The logging function to use to log, mmclog.h provides default_log - * to display information on the kernel output buffer. As a bonus if the - * requested log level is debug or trace the method , file and line number will - * be printed to the steam. - */ -struct mmclog { const char *name; int log_level; - - /* the logging function itself */ - void (*log_func) (struct mmclog * driver, - int level, - const char *file, - const char *function, int line, const char *fmt, ...); - -}; - -#define __mmc_log(driver,log_level, fmt, args...) \ - ((driver)->log_func(driver,log_level, \ - __FILE__, __FUNCTION__, __LINE__,\ - fmt, ## args)) - -/* Log a warning */ -#define mmc_log_warn(driver, fmt, args...) \ - __mmc_log(driver, LEVEL_WARN, fmt, ## args) - -/* Log an information message */ -#define mmc_log_info(driver, fmt, args...) \ - __mmc_log(driver, LEVEL_INFO, fmt, ## args) - -/* log debugging output */ -#define mmc_log_debug(driver, fmt, args...) \ - __mmc_log(driver, LEVEL_DEBUG, fmt, ## args) - -/* log trace output */ -#define mmc_log_trace(driver, fmt, args...) \ - __mmc_log(driver, LEVEL_TRACE, fmt, ## args) - -#endif /* __MMCLOG_H__ */ - -static void -default_log(struct mmclog *driver, - int level, - const char *file, const char *function, int line, const char *fmt, ...) -{ - va_list args; - - if (level > driver->log_level) { - return; - } - /* If the wanted level is debug also display line/method information */ - if (driver->log_level >= LEVEL_DEBUG) { - fprintf(stderr, "%s(%s):%s+%d(%s):", driver->name, - level_string[level], file, line, function); - } else { - fprintf(stderr, "%s(%s)", driver->name, level_string[level]); - } - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); -} - -#ifdef hacks -static void -hexdump(unsigned char *d, unsigned int size) -{ - int s; - for (s = 0; s < size; s += 4) { - fprintf(stdout, "0x%04x 0x%02X%02X%02X%02X %c%c%c%c\n", s, - (unsigned int) d[s], (unsigned int) d[s + 1], - (unsigned int) d[s + 2], (unsigned int) d[s + 3], d[s], - d[s + 1], d[s + 2], d[s + 3]); - } -} -#endif diff --git a/drivers/mmc/omap_mmc.h b/drivers/mmc/omap_mmc.h index 9c193c6aa..03ceefbf1 100644 --- a/drivers/mmc/omap_mmc.h +++ b/drivers/mmc/omap_mmc.h @@ -159,6 +159,9 @@ #define MMCHS_SD_STAT_CC (0x1 << 0) /* Command complete status */ #define MMCHS_SD_STAT_CC_UNRAISED (0x0 << 0) /* Command not completed */ #define MMCHS_SD_STAT_CC_RAISED (0x1 << 0) /* Command completed */ +#define MMCHS_SD_STAT_TC (0x1 << 1) /* Transfer complete status */ +#define MMCHS_SD_STAT_TC_UNRAISED (0x0 << 1) /* Transfer not completed */ +#define MMCHS_SD_STAT_TC_RAISED (0x1 << 1) /* Transfer completed */ #define MMCHS_SD_IE_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28)