summaryrefslogtreecommitdiff
path: root/drivers/mmc/mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/mmc.c')
-rw-r--r--drivers/mmc/mmc.c109
1 files changed, 105 insertions, 4 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 072ef46..9f915cd 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -91,6 +91,13 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
blklen = mmc->write_bl_len;
+#ifdef CONFIG_EMMC_DDR_MODE
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR) {
+ err = 0;
+ blklen = 512;
+ } else
+#endif
err = mmc_set_blocklen(mmc, mmc->write_bl_len);
if (err) {
@@ -173,6 +180,12 @@ int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size)
int endblock = lldiv(src + size - 1, mmc->read_bl_len);
int err = 0;
+#ifdef CONFIG_EMMC_DDR_MODE
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR)
+ blklen = 512;
+#endif
+
/* Make a buffer big enough to hold all the blocks we might read */
buffer = malloc(blklen);
@@ -181,6 +194,12 @@ int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size)
return -1;
}
+#ifdef CONFIG_EMMC_DDR_MODE
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR)
+ err = 0;
+ else
+#endif
/* We always do full block reads from the card */
err = mmc_set_blocklen(mmc, mmc->read_bl_len);
@@ -229,9 +248,14 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
if (!mmc)
return -1;
- blklen = mmc->read_bl_len;
-
- err = mmc_set_blocklen(mmc, blklen);
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR) {
+ blklen = 512;
+ err = 0;
+ } else {
+ blklen = mmc->read_bl_len;
+ err = mmc_set_blocklen(mmc, blklen);
+ }
if (err) {
puts("set read bl len failed\n\r");
@@ -444,7 +468,8 @@ static int mmc_change_freq(struct mmc *mmc)
if (mmc->version < MMC_VERSION_4)
return 0;
- mmc->card_caps |= MMC_MODE_4BIT;
+ mmc->card_caps |= ((mmc->host_caps & MMC_MODE_8BIT)
+ ? MMC_MODE_8BIT : MMC_MODE_4BIT);
ext_csd = (char *)malloc(512);
@@ -488,6 +513,15 @@ static int mmc_change_freq(struct mmc *mmc)
mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
else
mmc->card_caps |= MMC_MODE_HS;
+#ifdef CONFIG_EMMC_DDR_MODE
+ if (cardtype & EMMC_MODE_DDR_3V) {
+ if (mmc->card_caps & MMC_MODE_8BIT)
+ mmc->card_caps |= EMMC_MODE_8BIT_DDR;
+ else
+ mmc->card_caps |= EMMC_MODE_4BIT_DDR;
+ }
+
+#endif
no_err_rtn:
free(ext_csd);
@@ -681,6 +715,9 @@ int mmc_switch_partition(struct mmc *mmc, uint part, uint enable_boot)
int err;
uint old_part, new_part;
char boot_config;
+#ifdef CONFIG_EMMC_DDR_MODE
+ char boot_bus_width, card_boot_bus_width;
+#endif
/* partition must be -
0 - user area
@@ -765,6 +802,44 @@ int mmc_switch_partition(struct mmc *mmc, uint part, uint enable_boot)
goto err_rtn;
}
+#ifdef CONFIG_EMMC_DDR_MODE
+ /* Program boot_bus_width field for eMMC 4.4 boot mode */
+ if ((ext_csd[EXT_CSD_CARD_TYPE] & 0xC) && enable_boot != 0) {
+
+ /* Configure according to this host's capabilities */
+ if (mmc->host_caps & EMMC_MODE_8BIT_DDR)
+ boot_bus_width = EXT_CSD_BOOT_BUS_WIDTH_DDR |
+ EXT_CSD_BOOT_BUS_WIDTH_8BIT;
+ else if (mmc->host_caps & EMMC_MODE_4BIT_DDR)
+ boot_bus_width = EXT_CSD_BOOT_BUS_WIDTH_DDR |
+ EXT_CSD_BOOT_BUS_WIDTH_4BIT;
+ else if (mmc->host_caps & MMC_MODE_8BIT)
+ boot_bus_width = EXT_CSD_BOOT_BUS_WIDTH_8BIT;
+ else if (mmc->host_caps & MMC_MODE_4BIT)
+ boot_bus_width = EXT_CSD_BOOT_BUS_WIDTH_4BIT;
+ else
+ boot_bus_width = 0;
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_BUS_WIDTH, boot_bus_width);
+
+ /* Ensure that it programmed properly */
+ err = mmc_send_ext_csd(mmc, ext_csd);
+ if (err) {
+ puts("\nWarning: fail to get ext csd for MMC!\n");
+ goto err_rtn;
+ }
+
+ card_boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
+ if (card_boot_bus_width != boot_bus_width) {
+ printf("\nWarning: current boot_bus_width, 0x%x, is "
+ "not same as requested boot_bus_width 0x%x!\n",
+ card_boot_bus_width, boot_bus_width);
+ goto err_rtn;
+ }
+ }
+#endif
+
/* Seems everything is ok, return the partition id before switch */
free(ext_csd);
return old_part;
@@ -1023,6 +1098,32 @@ static int mmc_startup(struct mmc *mmc)
mmc_set_bus_width(mmc, 8);
}
+#ifdef CONFIG_EMMC_DDR_MODE
+
+ if (mmc->card_caps & EMMC_MODE_8BIT_DDR) {
+ /* Set the card to use 8 bit DDR mode */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ EXT_CSD_BUS_WIDTH_8_DDR);
+ if (err)
+ return err;
+
+
+ /* Setup the host controller for DDR mode */
+ mmc_set_bus_width(mmc, EMMC_MODE_8BIT_DDR);
+ } else if (mmc->card_caps & EMMC_MODE_4BIT_DDR) {
+ /* Set the card to use 4 bit DDR mode */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ EXT_CSD_BUS_WIDTH_4_DDR);
+ if (err)
+ return err;
+
+ /* Setup the host controller for DDR mode */
+ mmc_set_bus_width(mmc, EMMC_MODE_4BIT_DDR);
+ }
+#endif
+
if (mmc->card_caps & MMC_MODE_HS) {
if (mmc->card_caps & MMC_MODE_HS_52MHz)
mmc_set_clock(mmc, 52000000);