From 1bc5e5f2cee211a74ee79e0eb5f7f37a3db387f4 Mon Sep 17 00:00:00 2001 From: Anish Trivedi Date: Fri, 16 Jul 2010 12:35:32 -0500 Subject: ENGR00125036 Uboot Add eMMC 4.4 support Enable DDR mode on ESDHC controller and mmc library Enable 8-bit support in mmc library Signed-off-by: Anish Trivedi --- common/cmd_mmc.c | 6 ++ drivers/mmc/imx_esdhc.c | 55 +++++++++++++++++-- drivers/mmc/mmc.c | 109 +++++++++++++++++++++++++++++++++++-- include/configs/mx50_arm2.h | 6 +- include/configs/mx50_arm2_lpddr2.h | 7 ++- include/fsl_esdhc.h | 10 ++++ include/mmc.h | 12 +++- 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, ®s->cmdarg); writel(xfertyp, ®s->xfertyp); @@ -274,6 +279,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) while (!(readl(®s->irqstat) & IRQSTAT_TC)) ; } + if (readl(®s->irqstat) & 0xFFFF0000) + return COMM_ERR; + writel(-1, ®s->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(®s->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, ®s->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(®s->proctl) | PROCTL_DTW_8; writel(tmp, ®s->proctl); + } else if (mmc->bus_width == EMMC_MODE_4BIT_DDR) { + tmp = readl(®s->proctl) | PROCTL_DTW_4; + writel(tmp, ®s->proctl); + esdhc_dll_setup(mmc); + } else if (mmc->bus_width == EMMC_MODE_8BIT_DDR) { + tmp = readl(®s->proctl) | PROCTL_DTW_8; + writel(tmp, ®s->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(®s->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(®s->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) -- cgit v1.1