summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/cmd_mmc.c6
-rw-r--r--drivers/mmc/imx_esdhc.c55
-rw-r--r--drivers/mmc/mmc.c109
-rw-r--r--include/configs/mx50_arm2.h6
-rw-r--r--include/configs/mx50_arm2_lpddr2.h7
-rw-r--r--include/fsl_esdhc.h10
-rw-r--r--include/mmc.h12
7 files changed, 193 insertions, 12 deletions
diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index 1061dab..139b1e8 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -138,6 +138,12 @@ static void print_mmcinfo(struct mmc *mmc)
printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No");
printf("Capacity: %lld\n", mmc->capacity);
+#ifdef CONFIG_EMMC_DDR_MODE
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR)
+ printf("Bus Width: %d-bit DDR\n", (mmc->bus_width >> 8));
+ else
+#endif
printf("Bus Width: %d-bit\n", mmc->bus_width);
#ifdef CONFIG_BOOT_PARTITION_ACCESS
if (mmc->boot_size_mult == 0) {
diff --git a/drivers/mmc/imx_esdhc.c b/drivers/mmc/imx_esdhc.c
index e3a1fb7..a57aa74 100644
--- a/drivers/mmc/imx_esdhc.c
+++ b/drivers/mmc/imx_esdhc.c
@@ -69,10 +69,11 @@ struct fsl_esdhc {
uint wml;
char reserved1[8];
uint fevt;
- char reserved2[168];
+ char reserved2[12];
+ uint dllctrl;
+ uint dllstatus;
+ char reserved3[148];
uint hostver;
- char reserved3[780];
- uint scr;
};
/* Return the XFERTYP flags for a given command and data packet */
@@ -197,6 +198,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Figure out the transfer arguments */
xfertyp = esdhc_xfertyp(cmd, data);
+ if (mmc->bus_width == EMMC_MODE_4BIT_DDR ||
+ mmc->bus_width == EMMC_MODE_8BIT_DDR)
+ xfertyp |= XFERTYP_DDR_EN;
+
/* Send the command */
writel(cmd->cmdarg, &regs->cmdarg);
writel(xfertyp, &regs->xfertyp);
@@ -274,6 +279,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
while (!(readl(&regs->irqstat) & IRQSTAT_TC)) ;
}
+ if (readl(&regs->irqstat) & 0xFFFF0000)
+ return COMM_ERR;
+
writel(-1, &regs->irqstat);
return 0;
@@ -325,6 +333,22 @@ void set_sysctl(struct mmc *mmc, uint clock)
#endif
}
+static void esdhc_dll_setup(struct mmc *mmc)
+{
+ struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+ struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+
+ uint dll_control = readl(&regs->dllctrl);
+ dll_control &= ~(ESDHC_DLLCTRL_SLV_OVERRIDE_VAL_MASK |
+ ESDHC_DLLCTRL_SLV_OVERRIDE);
+ dll_control |= ((ESDHC_DLLCTRL_SLV_OVERRIDE_VAL <<
+ ESDHC_DLLCTRL_SLV_OVERRIDE_VAL_SHIFT) |
+ ESDHC_DLLCTRL_SLV_OVERRIDE);
+
+ writel(dll_control, &regs->dllctrl);
+
+}
+
static void esdhc_set_ios(struct mmc *mmc)
{
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
@@ -344,6 +368,14 @@ static void esdhc_set_ios(struct mmc *mmc)
} else if (mmc->bus_width == 8) {
tmp = readl(&regs->proctl) | PROCTL_DTW_8;
writel(tmp, &regs->proctl);
+ } else if (mmc->bus_width == EMMC_MODE_4BIT_DDR) {
+ tmp = readl(&regs->proctl) | PROCTL_DTW_4;
+ writel(tmp, &regs->proctl);
+ esdhc_dll_setup(mmc);
+ } else if (mmc->bus_width == EMMC_MODE_8BIT_DDR) {
+ tmp = readl(&regs->proctl) | PROCTL_DTW_8;
+ writel(tmp, &regs->proctl);
+ esdhc_dll_setup(mmc);
}
}
@@ -411,22 +443,35 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
mmc->set_ios = esdhc_set_ios;
mmc->init = esdhc_init;
- caps = regs->hostcapblt;
+ caps = readl(&regs->hostcapblt);
if (caps & ESDHC_HOSTCAPBLT_VS30)
mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & ESDHC_HOSTCAPBLT_VS33)
mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
+ mmc->host_caps = MMC_MODE_4BIT;
if (caps & ESDHC_HOSTCAPBLT_HSS)
mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+ if (((readl(&regs->hostver) & ESDHC_HOSTVER_VVN_MASK)
+ >> ESDHC_HOSTVER_VVN_SHIFT) >= ESDHC_HOSTVER_DDR_SUPPORT)
+ mmc->host_caps |= EMMC_MODE_4BIT_DDR;
+
mmc->f_min = 400000;
mmc->f_max = MIN(mxc_get_clock(MXC_ESDHC_CLK), 50000000);
mmc_register(mmc);
+#ifdef CONFIG_MMC_8BIT_PORTS
+ if ((1 << mmc->block_dev.dev) & CONFIG_MMC_8BIT_PORTS) {
+ mmc->host_caps |= MMC_MODE_8BIT;
+
+ if (mmc->host_caps & EMMC_MODE_4BIT_DDR)
+ mmc->host_caps |= EMMC_MODE_8BIT_DDR;
+ }
+#endif
+
return 0;
}
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);
diff --git a/include/configs/mx50_arm2.h b/include/configs/mx50_arm2.h
index fbede97..4c23b95 100644
--- a/include/configs/mx50_arm2.h
+++ b/include/configs/mx50_arm2.h
@@ -201,10 +201,14 @@
#define CONFIG_CMD_FAT 1
#define CONFIG_CMD_EXT2 1
- /* detect whether ESDHC1 or ESDHC3 is boot device */
+ /* detect whether ESDHC1, ESDHC2, or ESDHC3 is boot device */
#define CONFIG_DYNAMIC_MMC_DEVNO
#define CONFIG_BOOT_PARTITION_ACCESS
+ #define CONFIG_EMMC_DDR_MODE
+
+ /* Indicate to esdhc driver which ports support 8-bit data */
+ #define CONFIG_MMC_8BIT_PORTS 0x6 /* ports 1 and 2 */
#endif
/*-----------------------------------------------------------------------
diff --git a/include/configs/mx50_arm2_lpddr2.h b/include/configs/mx50_arm2_lpddr2.h
index 505b859..a5683ad 100644
--- a/include/configs/mx50_arm2_lpddr2.h
+++ b/include/configs/mx50_arm2_lpddr2.h
@@ -202,10 +202,15 @@
#define CONFIG_CMD_FAT 1
#define CONFIG_CMD_EXT2 1
- /* detect whether ESDHC1 or ESDHC3 is boot device */
+ /* detect whether ESDHC1, ESDHC2, or ESDHC3 is boot device */
#define CONFIG_DYNAMIC_MMC_DEVNO
#define CONFIG_BOOT_PARTITION_ACCESS
+ #define CONFIG_EMMC_DDR_MODE
+
+ /* Indicate to esdhc driver which ports support 8-bit data */
+ #define CONFIG_MMC_8BIT_PORTS 0x6 /* ports 1 and 2 */
+
#endif
/*-----------------------------------------------------------------------
diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h
index 9f48afe..a0b1f5c 100644
--- a/include/fsl_esdhc.h
+++ b/include/fsl_esdhc.h
@@ -116,6 +116,7 @@
#define XFERTYP_RSPTYP_48_BUSY 0x00030000
#define XFERTYP_MSBSEL 0x00000020
#define XFERTYP_DTDSEL 0x00000010
+#define XFERTYP_DDR_EN 0x00000008
#define XFERTYP_AC12EN 0x00000004
#define XFERTYP_BCEN 0x00000002
#define XFERTYP_DMAEN 0x00000001
@@ -146,6 +147,15 @@
#define ESDHC_HOSTCAPBLT_DMAS 0x00400000
#define ESDHC_HOSTCAPBLT_HSS 0x00200000
+#define ESDHC_HOSTVER_VVN_MASK 0x0000ff00
+#define ESDHC_HOSTVER_VVN_SHIFT 8
+#define ESDHC_HOSTVER_DDR_SUPPORT 0x13
+
+#define ESDHC_DLLCTRL_SLV_OVERRIDE_VAL 12
+#define ESDHC_DLLCTRL_SLV_OVERRIDE_VAL_MASK 0x0000FC00
+#define ESDHC_DLLCTRL_SLV_OVERRIDE_VAL_SHIFT 10
+#define ESDHC_DLLCTRL_SLV_OVERRIDE 0x200
+
struct fsl_esdhc_cfg {
u32 esdhc_base;
u32 no_snoop;
diff --git a/include/mmc.h b/include/mmc.h
index b8d6871..b450f4f 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -46,6 +46,8 @@
#define MMC_MODE_HS_52MHz 0x010
#define MMC_MODE_4BIT 0x100
#define MMC_MODE_8BIT 0x200
+#define EMMC_MODE_4BIT_DDR 0x400
+#define EMMC_MODE_8BIT_DDR 0x800
#define SD_DATA_4BIT 0x00040000
@@ -93,7 +95,7 @@
#define MMC_HS_TIMING 0x00000100
#define MMC_HS_52MHZ 0x2
-
+#define EMMC_MODE_DDR_3V 0x4
#define OCR_BUSY 0x80000000
#define OCR_HCS 0x40000000
@@ -131,6 +133,7 @@
* EXT_CSD fields
*/
+#define EXT_CSD_BOOT_BUS_WIDTH 177 /* RW */
#define EXT_CSD_BOOT_CONFIG 179 /* RW */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
@@ -153,6 +156,13 @@
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* eMMC 4.4 in 4-bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* eMMC 4.4 in 8-bit DDR mode */
+
+#define EXT_CSD_BOOT_BUS_WIDTH_1BIT 0
+#define EXT_CSD_BOOT_BUS_WIDTH_4BIT 1
+#define EXT_CSD_BOOT_BUS_WIDTH_8BIT 2
+#define EXT_CSD_BOOT_BUS_WIDTH_DDR (1 << 4)
#define EXT_CSD_BOOT_PARTITION_ENABLE_MASK (0x7 << 3)
#define EXT_CSD_BOOT_PARTITION_DISABLE (0x0)