arm:mmc driver refactor and timeout fix for BeagleBoneBlack.
When we send MMC commads that contain data the controller provides no description of the order of events and we need to be able to send data from and to the controller "when needed". Changed the code to react on buffer read and buffer write ready based on interrupts. Change-Id: I60c9140bf0e45b74be6475054564d4e1bd89f21e
This commit is contained in:
parent
8bac458ae9
commit
061fed753e
7 changed files with 254 additions and 369 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Makefile for the mmc driver.
|
# Makefile for the mmc driver.
|
||||||
PROG= mmc
|
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"
|
.if ${MACHINE_ARCH} == "earm"
|
||||||
|
|
|
@ -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
|
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.
|
like mmchost_mmchs to be split in a generic part and a specific part.
|
||||||
|
|
||||||
* Using interrupts
|
* 8 bits access
|
||||||
At time of writing the interrupt handlers on the ARM port are not implemented.
|
The driver currently only reads data over 1 or 4 bits address lines. Adding support
|
||||||
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
|
|
||||||
for 4 or 8 bits(for movinands) mode is very welcome.
|
for 4 or 8 bits(for movinands) mode is very welcome.
|
||||||
|
|
||||||
* DMA.
|
* DMA.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#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/log.h>
|
||||||
#include <minix/minlib.h>
|
#include <minix/minlib.h>
|
||||||
|
|
||||||
/* system headers */
|
/* system headers */
|
||||||
|
@ -20,10 +21,9 @@
|
||||||
|
|
||||||
/* local headers */
|
/* local headers */
|
||||||
#include "mmchost.h"
|
#include "mmchost.h"
|
||||||
#include "mmclog.h"
|
|
||||||
|
|
||||||
/* used for logging */
|
/* used for logging */
|
||||||
static struct mmclog log = {
|
static struct log log = {
|
||||||
.name = "mmc_block",
|
.name = "mmc_block",
|
||||||
.log_level = LEVEL_INFO,
|
.log_level = LEVEL_INFO,
|
||||||
.log_func = default_log
|
.log_func = default_log
|
||||||
|
@ -62,8 +62,7 @@ static void block_signal_handler_cb(int signo);
|
||||||
void
|
void
|
||||||
bdr_alarm(clock_t stamp)
|
bdr_alarm(clock_t stamp)
|
||||||
{
|
{
|
||||||
mmc_log_debug(&log, "alarm %d\n", stamp);
|
log_debug(&log, "alarm %d\n", stamp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_env();
|
static int apply_env();
|
||||||
|
@ -91,7 +90,7 @@ static struct blockdriver mmc_driver = {
|
||||||
static void
|
static void
|
||||||
hw_intr(unsigned int irqs)
|
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);
|
host.hw_intr(irqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +117,7 @@ apply_env()
|
||||||
} else if (strncmp(driver, "dummy", strlen("dummy") + 1) == 0) {
|
} else if (strncmp(driver, "dummy", strlen("dummy") + 1) == 0) {
|
||||||
host_initialize_host_structure_dummy(&host);
|
host_initialize_host_structure_dummy(&host);
|
||||||
} else {
|
} else {
|
||||||
mmc_log_warn(&log, "Unknown driver %s\n", driver);
|
log_warn(&log, "Unknown driver %s\n", driver);
|
||||||
}
|
}
|
||||||
/* Initialize the verbosity level. */
|
/* Initialize the verbosity level. */
|
||||||
v = 0;
|
v = 0;
|
||||||
|
@ -131,7 +130,7 @@ apply_env()
|
||||||
v = 0;
|
v = 0;
|
||||||
env_parse("instance", "d", 0, &v, 0, 3);
|
env_parse("instance", "d", 0, &v, 0, 3);
|
||||||
if (host.host_set_instance(&host, v)) {
|
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 -1; /* NOT OK */
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -153,15 +152,14 @@ block_open(dev_t minor, int access)
|
||||||
i = j = part_count = sub_part_count = 0;
|
i = j = part_count = sub_part_count = 0;
|
||||||
|
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
mmc_log_debug(&log,
|
log_debug(&log, "Not handling open on non existing slot\n");
|
||||||
"Not handling open on non existing slot\n");
|
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(slot->host != NULL);
|
assert(slot->host != NULL);
|
||||||
|
|
||||||
if (!slot->host->card_detect(slot)) {
|
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;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,14 +167,14 @@ block_open(dev_t minor, int access)
|
||||||
if (slot->card.state == SD_MODE_DATA_TRANSFER_MODE) {
|
if (slot->card.state == SD_MODE_DATA_TRANSFER_MODE) {
|
||||||
assert(slot->card.open_ct >= 0);
|
assert(slot->card.open_ct >= 0);
|
||||||
slot->card.open_ct++;
|
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);
|
slot->card.open_ct);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We did not have an sd-card inserted so we are going to probe for it
|
/* 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)) {
|
if (!host.card_initialize(slot)) {
|
||||||
// * TODO: set card state to INVALID until removed? */
|
// * TODO: set card state to INVALID until removed? */
|
||||||
return EIO;
|
return EIO;
|
||||||
|
@ -185,27 +183,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_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);
|
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_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);
|
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_trace(&log,
|
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_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);
|
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);
|
||||||
|
@ -222,8 +220,7 @@ block_close(dev_t minor)
|
||||||
|
|
||||||
slot = get_slot(minor);
|
slot = get_slot(minor);
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
mmc_log_debug(&log,
|
log_debug(&log, "Not handling open on non existing slot\n");
|
||||||
"Not handling open on non existing slot\n");
|
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,14 +233,13 @@ block_close(dev_t minor)
|
||||||
* return */
|
* return */
|
||||||
if (slot->card.open_ct > 1) {
|
if (slot->card.open_ct > 1) {
|
||||||
slot->card.open_ct--;
|
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);
|
slot->card.open_ct);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(slot->card.open_ct == 1);
|
assert(slot->card.open_ct == 1);
|
||||||
mmc_log_debug(&log,
|
log_debug(&log, "freeing the block device as it is no longer used\n");
|
||||||
"freeing the block device as it is no longer used\n");
|
|
||||||
|
|
||||||
/* release the card as check the open_ct should be 0 */
|
/* release the card as check the open_ct should be 0 */
|
||||||
slot->host->card_release(&slot->card);
|
slot->host->card_release(&slot->card);
|
||||||
|
@ -307,23 +303,23 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
/* Get the current "device" geometry */
|
/* Get the current "device" geometry */
|
||||||
dev = block_part(minor);
|
dev = block_part(minor);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Transfer requested on unknown device minor(%d)\n", minor);
|
"Transfer requested on unknown device minor(%d)\n", minor);
|
||||||
/* Unknown device */
|
/* Unknown device */
|
||||||
return ENXIO;
|
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);
|
(do_write) ? "Write" : "Read", position);
|
||||||
|
|
||||||
slot = get_slot(minor);
|
slot = get_slot(minor);
|
||||||
assert(slot);
|
assert(slot);
|
||||||
|
|
||||||
if (slot->card.blk_size == 0) {
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (slot->card.blk_size > COPYBUFF_SIZE) {
|
if (slot->card.blk_size > COPYBUFF_SIZE) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Card block size (%d) exceeds internal buffer size %d\n",
|
"Card block size (%d) exceeds internal buffer size %d\n",
|
||||||
slot->card.blk_size, COPYBUFF_SIZE);
|
slot->card.blk_size, COPYBUFF_SIZE);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
@ -333,7 +329,7 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
* parameters of transfers, in those cases we return EINVAL */
|
* parameters of transfers, in those cases we return EINVAL */
|
||||||
if (position % slot->card.blk_size != 0) {
|
if (position % slot->card.blk_size != 0) {
|
||||||
/* Starting at a block boundary */
|
/* Starting at a block boundary */
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Requests must start at a block boundary"
|
"Requests must start at a block boundary"
|
||||||
"(start,block size)=(%016llx,%08x)\n", position,
|
"(start,block size)=(%016llx,%08x)\n", position,
|
||||||
slot->card.blk_size);
|
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 */
|
/* Are we trying to start reading past the end */
|
||||||
if (position >= dev->dv_size) {
|
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;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -356,7 +352,7 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
assert(ciov != NULL);
|
assert(ciov != NULL);
|
||||||
if (ciov->iov_size % blk_size != 0) {
|
if (ciov->iov_size % blk_size != 0) {
|
||||||
/* transfer a multiple of blk_size */
|
/* transfer a multiple of blk_size */
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Requests must start at a block boundary "
|
"Requests must start at a block boundary "
|
||||||
"(start,block size)=(%016llx,%08x)\n", position,
|
"(start,block size)=(%016llx,%08x)\n", position,
|
||||||
slot->card.blk_size);
|
slot->card.blk_size);
|
||||||
|
@ -364,7 +360,7 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ciov->iov_size <= 0) {
|
if (ciov->iov_size <= 0) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Invalid iov size for iov %d of %d size\n",
|
"Invalid iov size for iov %d of %d size\n",
|
||||||
counter, nr_req, ciov->iov_size);
|
counter, nr_req, ciov->iov_size);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
@ -385,7 +381,7 @@ block_transfer(dev_t minor, /* minor device number */
|
||||||
io_size = dev->dv_size - (position + bytes_written);
|
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,"
|
"I/O %s request(%d/%d) iov(grant,size,iosize,"
|
||||||
"offset)=(%d,%d,%d,%d)\n",
|
"offset)=(%d,%d,%d,%d)\n",
|
||||||
(do_write) ? "write" : "read", counter + 1, nr_req,
|
(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,
|
i * blk_size, (vir_bytes) copybuff,
|
||||||
blk_size);
|
blk_size);
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"I/O write error: %s iov(base,size)=(%d,%d)"
|
"I/O write error: %s iov(base,size)=(%d,%d)"
|
||||||
" at offset=%d\n",
|
" at offset=%d\n",
|
||||||
strerror(_SIGN r), ciov->iov_addr,
|
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,
|
r = copyto(endpt, ciov->iov_addr, i * blk_size,
|
||||||
(vir_bytes) copybuff, blk_size);
|
(vir_bytes) copybuff, blk_size);
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"I/O read error: %s iov(base,size)=(%d,%d)"
|
"I/O read error: %s iov(base,size)=(%d,%d)"
|
||||||
" at offset=%d\n",
|
" at offset=%d\n",
|
||||||
strerror(_SIGN r), ciov->iov_addr,
|
strerror(_SIGN r), ciov->iov_addr,
|
||||||
|
@ -448,13 +444,13 @@ block_ioctl(dev_t minor,
|
||||||
{
|
{
|
||||||
/* IOCTL handling */
|
/* IOCTL handling */
|
||||||
struct sd_slot *slot;
|
struct sd_slot *slot;
|
||||||
mmc_log_trace(&log,
|
log_trace(&log,
|
||||||
"enter (minor,request,endpoint,grant)=(%d,%lu,%d)\n", minor,
|
"enter (minor,request,endpoint,grant)=(%d,%lu,%d)\n", minor,
|
||||||
request, endpt, grant);
|
request, endpt, grant);
|
||||||
|
|
||||||
slot = get_slot(minor);
|
slot = get_slot(minor);
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Doing ioctl on non existing block device(%d)\n", minor);
|
"Doing ioctl on non existing block device(%d)\n", minor);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -462,7 +458,7 @@ block_ioctl(dev_t minor,
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case DIOCOPENCT:
|
case DIOCOPENCT:
|
||||||
// TODO: add a check for card validity */
|
// 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);
|
slot->card.open_ct);
|
||||||
/* return the current open count */
|
/* return the current open count */
|
||||||
return sys_safecopyto(endpt, grant, 0,
|
return sys_safecopyto(endpt, grant, 0,
|
||||||
|
@ -496,14 +492,14 @@ block_part(dev_t minor)
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
slot = get_slot(minor);
|
slot = get_slot(minor);
|
||||||
if (!slot) {
|
if (!slot) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Device information requested for non existing partition "
|
"Device information requested for non existing partition "
|
||||||
"minor(%d)\n", minor);
|
"minor(%d)\n", minor);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!slot->host->card_detect(slot)) {
|
if (!slot->host->card_detect(slot)) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Device information requested from empty slot(%d)\n",
|
"Device information requested from empty slot(%d)\n",
|
||||||
minor);
|
minor);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -512,19 +508,19 @@ block_part(dev_t minor)
|
||||||
if (minor < 5) {
|
if (minor < 5) {
|
||||||
/* we are talking about the first disk */
|
/* we are talking about the first disk */
|
||||||
dev = &slot->card.part[minor];
|
dev = &slot->card.part[minor];
|
||||||
mmc_log_trace(&log,
|
log_trace(&log,
|
||||||
"returning partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
|
"returning partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
|
||||||
minor, dev->dv_base, dev->dv_size);
|
minor, dev->dv_base, dev->dv_size);
|
||||||
} else if (minor >= 128 && minor < 128 + 16) {
|
} else if (minor >= 128 && minor < 128 + 16) {
|
||||||
/* sub partitions of the first disk we don't care about the
|
/* sub partitions of the first disk we don't care about the
|
||||||
* rest */
|
* rest */
|
||||||
dev = &slot->card.subpart[minor - 128];
|
dev = &slot->card.subpart[minor - 128];
|
||||||
mmc_log_trace(&log,
|
log_trace(&log,
|
||||||
"returning sub partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
|
"returning sub partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
|
||||||
minor - 128, dev->dv_base, dev->dv_size);
|
minor - 128, dev->dv_base, dev->dv_size);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Device information requested for non existing "
|
"Device information requested for non existing "
|
||||||
"partition minor(%d)\n", minor);
|
"partition minor(%d)\n", minor);
|
||||||
}
|
}
|
||||||
|
@ -537,16 +533,14 @@ block_part(dev_t minor)
|
||||||
static void
|
static void
|
||||||
sef_local_startup()
|
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()) {
|
if (apply_env()) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "Failed while applying environment settings\n");
|
||||||
"Failed while applying environment settings\n");
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host.host_init(&host)) {
|
if (host.host_init(&host)) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "Failed to initialize the host controller\n");
|
||||||
"Failed to initialize the host controller\n");
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -574,16 +568,16 @@ block_system_event_cb(int type, sef_init_info_t * info)
|
||||||
* sef_local_startup */
|
* sef_local_startup */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SEF_INIT_FRESH:
|
case SEF_INIT_FRESH:
|
||||||
mmc_log_info(&log, "System event framework fresh start\n");
|
log_info(&log, "System event framework fresh start\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEF_INIT_LU:
|
case SEF_INIT_LU:
|
||||||
/* Restore the state. post update */
|
/* 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;
|
break;
|
||||||
|
|
||||||
case SEF_INIT_RESTART:
|
case SEF_INIT_RESTART:
|
||||||
mmc_log_info(&log, "System event framework post restart\n");
|
log_info(&log, "System event framework post restart\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
blockdriver_announce(type);
|
blockdriver_announce(type);
|
||||||
|
@ -598,7 +592,7 @@ block_signal_handler_cb(int signo)
|
||||||
{
|
{
|
||||||
struct sd_slot *slot;
|
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);
|
signo);
|
||||||
/* Only check for termination signal, ignore anything else. */
|
/* Only check for termination signal, ignore anything else. */
|
||||||
if (signo != SIGTERM)
|
if (signo != SIGTERM)
|
||||||
|
@ -609,12 +603,12 @@ block_signal_handler_cb(int signo)
|
||||||
slot = get_slot(0);
|
slot = get_slot(0);
|
||||||
assert(slot);
|
assert(slot);
|
||||||
if (slot->card.open_ct > 0) {
|
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);
|
slot->card.open_ct);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmc_log_info(&log, "MMC driver exit");
|
log_info(&log, "MMC driver exit");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +636,7 @@ get_slot(dev_t minor)
|
||||||
/* a minor from the first disk */
|
/* a minor from the first disk */
|
||||||
return &host.slot[0];
|
return &host.slot[0];
|
||||||
} else {
|
} else {
|
||||||
mmc_log_trace(&log,
|
log_trace(&log,
|
||||||
"Device information requested for non existing partition "
|
"Device information requested for non existing partition "
|
||||||
"minor(%d)\n", minor);
|
"minor(%d)\n", minor);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -655,7 +649,7 @@ set_log_level(int level)
|
||||||
if (level < 0 || level >= 4) {
|
if (level < 0 || level >= 4) {
|
||||||
return;
|
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;
|
log.log_level = level;
|
||||||
if (host.set_log_level) {
|
if (host.set_log_level) {
|
||||||
host.set_log_level(level);
|
host.set_log_level(level);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* kernel headers */
|
/* kernel headers */
|
||||||
#include <minix/blockdriver.h>
|
#include <minix/blockdriver.h>
|
||||||
#include <minix/minlib.h>
|
#include <minix/minlib.h>
|
||||||
|
#include <minix/log.h>
|
||||||
|
|
||||||
/* usr headers */
|
/* usr headers */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -10,14 +11,13 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* local headers */
|
/* local headers */
|
||||||
#include "mmclog.h"
|
|
||||||
#include "mmchost.h"
|
#include "mmchost.h"
|
||||||
#include "sdmmcreg.h"
|
#include "sdmmcreg.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define a structure to be used for logging
|
* Define a structure to be used for logging
|
||||||
*/
|
*/
|
||||||
static struct mmclog log = {
|
static struct log log = {
|
||||||
.name = "mmc_host_memory",
|
.name = "mmc_host_memory",
|
||||||
.log_level = LEVEL_INFO,
|
.log_level = LEVEL_INFO,
|
||||||
.log_func = default_log
|
.log_func = default_log
|
||||||
|
@ -36,7 +36,7 @@ init_dummy_sdcard(struct sd_slot *slot)
|
||||||
|
|
||||||
assert(slot != NULL);
|
assert(slot != NULL);
|
||||||
|
|
||||||
mmc_log_info(&log, "Using a dummy card \n");
|
log_info(&log, "Using a dummy card \n");
|
||||||
if (dummy_data == NULL) {
|
if (dummy_data == NULL) {
|
||||||
dummy_data = malloc(DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS);
|
dummy_data = malloc(DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS);
|
||||||
if (dummy_data == NULL) {
|
if (dummy_data == NULL) {
|
||||||
|
@ -81,7 +81,7 @@ dummy_set_log_level(int level)
|
||||||
int
|
int
|
||||||
dummy_host_set_instance(struct mmc_host *host, int instance)
|
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) {
|
if (instance != 0) {
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <minix/com.h>
|
#include <minix/com.h>
|
||||||
#include <minix/vm.h>
|
#include <minix/vm.h>
|
||||||
#include <minix/spin.h>
|
#include <minix/spin.h>
|
||||||
|
#include <minix/log.h>
|
||||||
#include <minix/mmio.h>
|
#include <minix/mmio.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -18,7 +19,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* local headers */
|
/* local headers */
|
||||||
#include "mmclog.h"
|
|
||||||
#include "mmchost.h"
|
#include "mmchost.h"
|
||||||
|
|
||||||
/* header imported from netbsd */
|
/* header imported from netbsd */
|
||||||
|
@ -41,12 +41,12 @@ static int hook_id = 1;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SANE_TIMEOUT 500000 /* 500 MS */
|
#define SANE_TIMEOUT 500000 /* 500 ms */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define a structure to be used for logging
|
* Define a structure to be used for logging
|
||||||
*/
|
*/
|
||||||
static struct mmclog log = {
|
static struct log log = {
|
||||||
.name = "mmc_host_mmchs",
|
.name = "mmc_host_mmchs",
|
||||||
.log_level = LEVEL_INFO,
|
.log_level = LEVEL_INFO,
|
||||||
.log_func = default_log
|
.log_func = default_log
|
||||||
|
@ -98,7 +98,7 @@ mmchs_init(uint32_t instance)
|
||||||
while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
|
while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
|
||||||
& MMCHS_SD_SYSSTATUS_RESETDONE)) {
|
& MMCHS_SD_SYSSTATUS_RESETDONE)) {
|
||||||
if (spin_check(&spin) == FALSE) {
|
if (spin_check(&spin) == FALSE) {
|
||||||
mmc_log_warn(&log, "mmc init timeout\n");
|
log_warn(&log, "mmc init timeout\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ mmchs_init(uint32_t instance)
|
||||||
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) {
|
||||||
if (spin_check(&spin) == FALSE) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,9 +181,8 @@ mmchs_init(uint32_t instance)
|
||||||
spin_init(&spin, SANE_TIMEOUT);
|
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) {
|
||||||
|
|
||||||
if (spin_check(&spin) == FALSE) {
|
if (spin_check(&spin) == FALSE) {
|
||||||
mmc_log_warn(&log, "clock not stable\n");
|
log_warn(&log, "clock not stable\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,9 +199,7 @@ mmchs_init(uint32_t instance)
|
||||||
MMCHS_SD_IE_TC_ENABLE_ENABLE);
|
MMCHS_SD_IE_TC_ENABLE_ENABLE);
|
||||||
|
|
||||||
/* enable error interrupts */
|
/* enable error interrupts */
|
||||||
/* NOTE: We are currently skipping the BADA interrupt it does get
|
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0xffffffffu);
|
||||||
* raised for unknown reasons */
|
|
||||||
set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0x0fffffffu);
|
|
||||||
|
|
||||||
/* clear the error interrupts */
|
/* clear the error interrupts */
|
||||||
set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
|
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)
|
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) {
|
||||||
mmc_log_warn(&log, "%s, error stat %x\n",
|
log_warn(&log, "%s, error stat %x\n",
|
||||||
__FUNCTION__,
|
__FUNCTION__,
|
||||||
read32(base_address + MMCHS_SD_STAT));
|
read32(base_address + MMCHS_SD_STAT));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spin_check(&spin) == FALSE) {
|
if (spin_check(&spin) == FALSE) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "Interrupt not raised during init\n");
|
||||||
"Interrupt not raised during init\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,10 +257,86 @@ mmchs_init(uint32_t instance)
|
||||||
return 0;
|
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
|
static void
|
||||||
mmchs_hw_intr(unsigned int irqs)
|
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
|
#ifdef USE_INTR
|
||||||
if (sys_irqenable(&hook_id) != OK)
|
if (sys_irqenable(&hook_id) != OK)
|
||||||
|
@ -300,27 +372,47 @@ intr_wait(int mask)
|
||||||
switch (_ENDPOINT_P(m.m_source)) {
|
switch (_ENDPOINT_P(m.m_source)) {
|
||||||
case CLOCK:
|
case CLOCK:
|
||||||
/* Timeout. */
|
/* Timeout. */
|
||||||
// w_timeout(); /* a.o. set w_status */
|
log_warn(&log, "TIMEOUT\n");
|
||||||
mmc_log_warn(&log, "TIMEOUT\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
case HARDWARE:
|
case HARDWARE:
|
||||||
v = read32(base_address + MMCHS_SD_STAT);
|
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) {
|
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);
|
sys_setalarm(0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (v & (1 << 15)) {
|
} else if (v & (1 << 15)) {
|
||||||
return 1; /* error */
|
return 1; /* error */
|
||||||
} else {
|
}
|
||||||
mmc_log_debug(&log,
|
|
||||||
|
log_warn(&log,
|
||||||
"unexpected HW interrupt 0x%08x mask 0X%08x\n",
|
"unexpected HW interrupt 0x%08x mask 0X%08x\n",
|
||||||
v, mask);
|
v, mask);
|
||||||
if (sys_irqenable(&hook_id) != OK)
|
if (sys_irqenable(&hook_id) != OK)
|
||||||
printf
|
printf
|
||||||
("Failed to re-enable irqenable irq\n");
|
("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:
|
default:
|
||||||
/*
|
/*
|
||||||
* unhandled message. queue it and
|
* unhandled message. queue it and
|
||||||
|
@ -329,7 +421,6 @@ intr_wait(int mask)
|
||||||
blockdriver_mq_queue(&m, ipc_status);
|
blockdriver_mq_queue(&m, ipc_status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mmc_log_debug(&log, "Other\n");
|
|
||||||
/*
|
/*
|
||||||
* unhandled message. queue it and handle it in the
|
* unhandled message. queue it and handle it in the
|
||||||
* blockdriver loop.
|
* blockdriver loop.
|
||||||
|
@ -348,15 +439,23 @@ intr_wait(int mask)
|
||||||
counter++;
|
counter++;
|
||||||
v = read32(base_address + MMCHS_SD_STAT);
|
v = read32(base_address + MMCHS_SD_STAT);
|
||||||
if (spin_check(&spin) == FALSE) {
|
if (spin_check(&spin) == FALSE) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log,
|
||||||
"Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",
|
"Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",
|
||||||
counter, v, mask);
|
counter, v, mask);
|
||||||
return 1;
|
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) {
|
if (v & mask) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (v & 0xFF00) {
|
} else if (v & 0xFF00) {
|
||||||
mmc_log_debug(&log,
|
log_debug(&log,
|
||||||
"unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n",
|
"unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n",
|
||||||
v, mask);
|
v, mask);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -366,36 +465,26 @@ intr_wait(int mask)
|
||||||
#endif /* USE_INTR */
|
#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)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Read current interrupt status and fail it an interrupt is already
|
/* Read current interrupt status and fail it an interrupt is already
|
||||||
* asserted */
|
* asserted */
|
||||||
|
assert(read32(base_address + MMCHS_SD_STAT) == 0);
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
||||||
if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
|
if (intr_wait(MMCHS_SD_STAT_CC)) {
|
||||||
intr_assert(MMCHS_SD_STAT_CC);
|
uint32_t v = read32(base_address + MMCHS_SD_STAT);
|
||||||
mmc_log_warn(&log, "Failure waiting for interrupt\n");
|
intr_deassert(MMCHS_SD_STAT_CC);
|
||||||
|
log_warn(&log, "Failure waiting for interrupt 0x%lx\n", v);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
intr_deassert(MMCHS_SD_STAT_CC);
|
||||||
|
|
||||||
if ((command & MMCHS_SD_CMD_RSP_TYPE) ==
|
if ((command & MMCHS_SD_CMD_RSP_TYPE) ==
|
||||||
MMCHS_SD_CMD_RSP_TYPE_48B_BUSY) {
|
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)
|
if ((read32(base_address + MMCHS_SD_STAT)
|
||||||
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
|
& MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
|
||||||
mmc_log_warn(&log, "TC should be raised\n");
|
log_warn(&log, "TC should be raised\n");
|
||||||
}
|
}
|
||||||
write32(base_address + MMCHS_SD_STAT,
|
intr_deassert(MMCHS_SD_STAT_TC);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
intr_assert(MMCHS_SD_STAT_CC);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,8 +507,6 @@ mmc_send_cmd(struct mmc_command *c)
|
||||||
/* convert the command to a hsmmc command */
|
/* convert the command to a hsmmc command */
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t cmd, arg;
|
uint32_t cmd, arg;
|
||||||
uint32_t count;
|
|
||||||
uint32_t value;
|
|
||||||
cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
|
cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
|
||||||
arg = c->args;
|
arg = c->args;
|
||||||
|
|
||||||
|
@ -449,11 +528,10 @@ mmc_send_cmd(struct mmc_command *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read single block */
|
/* 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_DP_DATA; /* Command with data transfer */
|
||||||
cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */
|
cmd |= MMCHS_SD_CMD_MSBS_SINGLE; /* single block */
|
||||||
cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */
|
cmd |= MMCHS_SD_CMD_DDIR_READ; /* read data from card */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write single block */
|
/* write single block */
|
||||||
|
@ -465,7 +543,7 @@ mmc_send_cmd(struct mmc_command *c)
|
||||||
|
|
||||||
/* check we are in a sane state */
|
/* check we are in a sane state */
|
||||||
if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
|
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));
|
__FUNCTION__, read32(base_address + MMCHS_SD_STAT));
|
||||||
write32(base_address + MMCHS_SD_STAT,
|
write32(base_address + MMCHS_SD_STAT,
|
||||||
MMCHS_SD_IE_CC_ENABLE_CLEAR);
|
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,
|
||||||
MMCHS_SD_IE_BWR_ENABLE_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);
|
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 */
|
/* copy response into cmd->resp */
|
||||||
switch (c->resp_type) {
|
switch (c->resp_type) {
|
||||||
case RESP_LEN_48_CHK_BUSY:
|
case RESP_LEN_48_CHK_BUSY:
|
||||||
|
@ -507,98 +623,6 @@ mmc_send_cmd(struct mmc_command *c)
|
||||||
return 1;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,14 +666,13 @@ card_identification()
|
||||||
if (mmc_send_cmd(&command)) {
|
if (mmc_send_cmd(&command)) {
|
||||||
/* We currently only support 2.0, and 1.0 won't respond to
|
/* We currently only support 2.0, and 1.0 won't respond to
|
||||||
* this request */
|
* this request */
|
||||||
mmc_log_warn(&log, "%s, non SDHC card inserted\n",
|
log_warn(&log, "%s, non SDHC card inserted\n", __FUNCTION__);
|
||||||
__FUNCTION__);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(command.resp[0]
|
if (!(command.resp[0]
|
||||||
== (MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN))) {
|
== (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]);
|
__FUNCTION__, command.resp[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -661,13 +684,6 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
||||||
{
|
{
|
||||||
struct mmc_command command;
|
struct mmc_command command;
|
||||||
spin_t spin;
|
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.cmd = SD_APP_OP_COND;
|
||||||
command.resp_type = RESP_LEN_48;
|
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;
|
MMC_OCR_2_7V_2_8V;
|
||||||
command.args |= MMC_OCR_HCS; /* RCA=0000 */
|
command.args |= MMC_OCR_HCS; /* RCA=0000 */
|
||||||
|
|
||||||
if (mmc_send_cmd(&command)) {
|
if (mmc_send_app_cmd(card, &command)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* @todo wait for max 1 ms */
|
/* @todo wait for max 1 ms */
|
||||||
spin_init(&spin, SANE_TIMEOUT);
|
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.resp_type = RESP_LEN_48;
|
|
||||||
command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */
|
|
||||||
if (mmc_send_cmd(&command)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send ADMD41 */
|
/* Send ADMD41 */
|
||||||
/* 0x1 << 30 == send HCS (Host capacity support) and get OCR
|
/* 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;
|
| MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V;
|
||||||
command.args |= MMC_OCR_HCS; /* RCA=0000 */
|
command.args |= MMC_OCR_HCS; /* RCA=0000 */
|
||||||
|
|
||||||
if (mmc_send_cmd(&command)) {
|
if (mmc_send_app_cmd(card, &command)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,8 +722,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (spin_check(&spin) == FALSE) {
|
if (spin_check(&spin) == FALSE) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "TIMEOUT waiting for the SD card\n");
|
||||||
"TIMEOUT waiting for the SD card\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -777,12 +786,12 @@ card_csd(struct sd_card_regs *card)
|
||||||
card->csd[3] = command.resp[3];
|
card->csd[3] = command.resp[3];
|
||||||
|
|
||||||
if (SD_CSD_CSDVER(card->csd) != SD_CSD_CSDVER_2_0) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sanity check */
|
/* 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);
|
// unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -801,7 +810,6 @@ select_card(struct sd_card_regs *card)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
read_single_block(struct sd_card_regs *card,
|
read_single_block(struct sd_card_regs *card,
|
||||||
uint32_t blknr, unsigned char *buf)
|
uint32_t blknr, unsigned char *buf)
|
||||||
|
@ -815,7 +823,7 @@ read_single_block(struct sd_card_regs *card,
|
||||||
command.data_len = 512;
|
command.data_len = 512;
|
||||||
|
|
||||||
if (mmc_send_cmd(&command)) {
|
if (mmc_send_cmd(&command)) {
|
||||||
mmc_log_warn(&log, "Error sending command\n");
|
log_warn(&log, "Error sending command\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,8 +836,6 @@ write_single_block(struct sd_card_regs *card,
|
||||||
{
|
{
|
||||||
struct mmc_command command;
|
struct mmc_command command;
|
||||||
|
|
||||||
set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
|
|
||||||
|
|
||||||
command.cmd = MMC_WRITE_BLOCK_SINGLE;
|
command.cmd = MMC_WRITE_BLOCK_SINGLE;
|
||||||
command.args = blknr;
|
command.args = blknr;
|
||||||
command.resp_type = RESP_LEN_48;
|
command.resp_type = RESP_LEN_48;
|
||||||
|
@ -838,7 +844,7 @@ write_single_block(struct sd_card_regs *card,
|
||||||
|
|
||||||
/* write single block */
|
/* write single block */
|
||||||
if (mmc_send_cmd(&command)) {
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,7 +869,7 @@ mmchs_set_log_level(int level)
|
||||||
int
|
int
|
||||||
mmchs_host_set_instance(struct mmc_host *host, int instance)
|
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) {
|
if (instance != 0) {
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
@ -895,40 +901,38 @@ mmchs_card_initialize(struct sd_slot *slot)
|
||||||
card->slot = slot;
|
card->slot = slot;
|
||||||
|
|
||||||
if (card_goto_idle_state()) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card_identification()) {
|
if (card_identification()) {
|
||||||
mmc_log_warn(&log, "Failed to do card_identification\n");
|
log_warn(&log, "Failed to do card_identification\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card_query_voltage_and_type(&slot->card.regs)) {
|
if (card_query_voltage_and_type(&slot->card.regs)) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "Failed to do card_query_voltage_and_type\n");
|
||||||
"Failed to do card_query_voltage_and_type\n");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (card_identify(&slot->card.regs)) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* We have now initialized the hardware identified the card */
|
/* We have now initialized the hardware identified the card */
|
||||||
if (card_csd(&slot->card.regs)) {
|
if (card_csd(&slot->card.regs)) {
|
||||||
mmc_log_warn(&log,
|
log_warn(&log, "failed to read csd (card specific data)\n");
|
||||||
"failed to read csd (card specific data)\n");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select_card(&slot->card.regs)) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SD_CSD_READ_BL_LEN(slot->card.regs.csd) != 0x09) {
|
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
|
/* for CSD version 2.0 the value is fixed to 0x09 and means a
|
||||||
* block size of 512 */
|
* 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,6 +985,7 @@ mmchs_card_release(struct sd_card *card)
|
||||||
card->open_ct--;
|
card->open_ct--;
|
||||||
card->state = SD_MODE_UNINITIALIZED;
|
card->state = SD_MODE_UNINITIALIZED;
|
||||||
/* TODO:Set card state */
|
/* TODO:Set card state */
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -159,6 +159,9 @@
|
||||||
#define MMCHS_SD_STAT_CC (0x1 << 0) /* Command complete status */
|
#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_UNRAISED (0x0 << 0) /* Command not completed */
|
||||||
#define MMCHS_SD_STAT_CC_RAISED (0x1 << 0) /* Command 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)
|
#define MMCHS_SD_IE_ERROR_MASK (0xff << 15 | 0x3 << 24 | 0x03 << 28)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue