summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2014-02-11 17:57:48 (GMT)
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-02-19 18:35:51 (GMT)
commit5b6ef73f27fff5ebe2adb7132acc9b3a3374edc4 (patch)
tree6bd5c77d730fd85c84db2bd173f32d1715affe97
parent97583190da4252f458f4de1d14fc79b729a98dc8 (diff)
downloaddepthcharge-stabilize-5511.B.tar.gz
depthcharge-stabilize-5511.B.tar.xz
SD card support in SDHCI driverstabilize-5511.Bfactory-rambi-5517.B
The SDHCI driver is being modified and refactored to support both eMMC and SD media. While debugging SD card operations it was discovered, that the host controller behaves differently when communicating with the SD cards. One of the fundamental differences between eMMC and SD is that SD cards allow arbitrary power of 2 block sizes for data transfers, whereas eMMC devices support only single fixed block size. Furthermore, even though the SDHCI controller specification describes the block count register as follows: "This register is enabled when Block Count Enable in the Transfer Mode register is set to 1 and is valid only for multiple block transfers." in reality. for single block SD card data transfers the controller Block Count register must be set to 1, if it is not - the following multiblock transfer times out. The CD card presence logic is modified to match Rambi hardware. BUG=chrome-os-partner:24396 TEST=manual . with these modifications Rambi successfully boots from both eMMC and SD card. Change-Id: Ic58fd40c08802b72f15003f5c0fae2c4cc14ca7c Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/185890 Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
-rw-r--r--src/drivers/storage/sdhci.c82
1 files changed, 40 insertions, 42 deletions
diff --git a/src/drivers/storage/sdhci.c b/src/drivers/storage/sdhci.c
index cbf6659..c0a6ac5 100644
--- a/src/drivers/storage/sdhci.c
+++ b/src/drivers/storage/sdhci.c
@@ -113,7 +113,6 @@ static int sdhci_setup_adma(SdhciHost *host, MmcData* data)
{
int i, togo, need_descriptors;
char *buffer_data;
- u16 mode = SDHCI_TRNS_DMA;
togo = data->blocks * data->blocksize;
if (!togo) {
@@ -164,20 +163,10 @@ static int sdhci_setup_adma(SdhciHost *host, MmcData* data)
sdhci_writel(host, (u32) host->adma_descs, SDHCI_ADMA_ADDRESS);
- if (data->blocks > 1) {
- mode |= SDHCI_TRNS_MULTI |
- SDHCI_TRNS_BLK_CNT_EN |
- SDHCI_TRNS_ACMD12;
- }
- if (data->flags == MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
-
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
-
return 0;
}
-static int sdhci_complete_adma(SdhciHost *host)
+static int sdhci_complete_adma(SdhciHost *host, MmcCommand *cmd)
{
int retry;
u32 stat = 0, mask;
@@ -208,14 +197,15 @@ static int sdhci_complete_adma(SdhciHost *host)
udelay(1);
}
- sdhci_writel(host, SDHCI_INT_DATA_END | SDHCI_INT_ADMA_ERROR,
- SDHCI_INT_STATUS);
- if (!(stat & SDHCI_INT_ERROR))
+ sdhci_writel(host, stat, SDHCI_INT_STATUS);
+ if (retry && !(stat & SDHCI_INT_ERROR)) {
+ sdhci_cmd_done(host, cmd);
return 0;
+ }
}
- printf("%s: transfer error, stat %#x, adma error %#x\n",
- __func__, stat, sdhci_readl(host, SDHCI_ADMA_ERROR));
+ printf("%s: transfer error, stat %#x, adma error %#x, retry %d\n",
+ __func__, stat, sdhci_readl(host, SDHCI_ADMA_ERROR), retry);
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
@@ -231,13 +221,13 @@ static int sdhci_send_command(MmcCtrlr *mmc_ctrl, MmcCommand *cmd,
{
unsigned int stat = 0;
int ret = 0;
- u32 mask, flags, mode;
+ u32 mask, flags;
unsigned int timeout, start_addr = 0;
unsigned int retry = 10000;
SdhciHost *host = container_of(mmc_ctrl, SdhciHost, mmc_ctrlr);
- /* Wait max 10 ms */
- timeout = 10;
+ /* Wait max 1 s */
+ timeout = 1000;
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
@@ -249,7 +239,9 @@ static int sdhci_send_command(MmcCtrlr *mmc_ctrl, MmcCommand *cmd,
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
- printf("Controller never released inhibit bit(s).\n");
+ printf("Controller never released inhibit bit(s), "
+ "present state %#8.8x.\n",
+ sdhci_readl(host, SDHCI_PRESENT_STATE));
return MMC_COMM_ERR;
}
timeout--;
@@ -276,32 +268,35 @@ static int sdhci_send_command(MmcCtrlr *mmc_ctrl, MmcCommand *cmd,
/*Set Transfer mode regarding to data flag*/
if (data) {
- if (host->host_caps & MMC_AUTO_CMD12) {
- if (sdhci_setup_adma(host, data))
- return -1;
- } else { /* Set up non dma transfer */
-
- sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
- mode = SDHCI_TRNS_BLK_CNT_EN;
- if (data->blocks > 1)
- mode |= SDHCI_TRNS_MULTI;
-
- if (data->flags == MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
+ u16 mode = 0;
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
- }
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
data->blocksize),
SDHCI_BLOCK_SIZE);
+
+ if (data->flags == MMC_DATA_READ)
+ mode |= SDHCI_TRNS_READ;
+
+ if (data->blocks > 1)
+ mode |= SDHCI_TRNS_BLK_CNT_EN |
+ SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
+
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+ if (host->host_caps & MMC_AUTO_CMD12) {
+ if (sdhci_setup_adma(host, data))
+ return -1;
+
+ mode |= SDHCI_TRNS_DMA;
+ }
+ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
}
sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
if (data && (host->host_caps & MMC_AUTO_CMD12))
- return sdhci_complete_adma(host);
+ return sdhci_complete_adma(host, cmd);
do {
stat = sdhci_readl(host, SDHCI_INT_STATUS);
@@ -603,6 +598,9 @@ static int sdhci_init(SdhciHost *host)
/* Mask all sdhci interrupt sources */
sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
+ /* Set timeout to maximum, shouldn't happen if everything's right. */
+ sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
+
udelay(10000);
return 0;
}
@@ -613,8 +611,8 @@ static int sdhci_update(BlockDevCtrlrOps *me)
(me, SdhciHost, mmc_ctrlr.ctrlr.ops);
if (host->removable) {
- int present = !(sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT);
+ int present = (sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT) != 0;
if (present && !host->mmc_ctrlr.media) {
// A card is present and not set up yet. Get it ready.
@@ -625,8 +623,6 @@ static int sdhci_update(BlockDevCtrlrOps *me)
return -1;
host->mmc_ctrlr.media->dev.name = "SDHCI card";
host->mmc_ctrlr.media->dev.removable = 1;
- host->mmc_ctrlr.media->dev.ops.read = &block_mmc_read;
- host->mmc_ctrlr.media->dev.ops.write = &block_mmc_write;
list_insert_after(&host->mmc_ctrlr.media->dev.list_node,
&removable_block_devices);
} else if (!present && host->mmc_ctrlr.media) {
@@ -645,12 +641,14 @@ static int sdhci_update(BlockDevCtrlrOps *me)
return -1;
host->mmc_ctrlr.media->dev.name = "SDHCI fixed";
host->mmc_ctrlr.media->dev.removable = 0;
- host->mmc_ctrlr.media->dev.ops.read = &block_mmc_read;
- host->mmc_ctrlr.media->dev.ops.write = &block_mmc_write;
list_insert_after(&host->mmc_ctrlr.media->dev.list_node,
&fixed_block_devices);
host->mmc_ctrlr.ctrlr.need_update = 0;
}
+
+ host->mmc_ctrlr.media->dev.ops.read = block_mmc_read;
+ host->mmc_ctrlr.media->dev.ops.write = block_mmc_write;
+
return 0;
}