From 82102d3fdeae0dcd79d9b3ab7daa96bebd5ad290 Mon Sep 17 00:00:00 2001 From: Anish Trivedi Date: Wed, 22 Jun 2011 17:49:45 -0500 Subject: ENGR00139206 MX6 USDHC eMMC 4.4 support New bit definitions in USDHC. Added is_usdhc variable to fsl_esdhc_cfg to distinguish between ESDHC and USDHC. Enabled DDR mode support in USDHC. Created a config to customize target delay for DDR mode. Modified USDHC pad settings to make DDR mode work for all emmcs at 50 MHz. Signed-off-by: Anish Trivedi --- board/freescale/mx6q_sabreauto/mx6q_sabreauto.c | 21 ++++++++-- drivers/mmc/imx_esdhc.c | 56 ++++++++++++++++++------- include/asm-arm/arch-mx6/mx6_pins.h | 4 +- include/configs/mx6q_sabreauto.h | 2 + include/fsl_esdhc.h | 16 +++++-- 5 files changed, 75 insertions(+), 24 deletions(-) diff --git a/board/freescale/mx6q_sabreauto/mx6q_sabreauto.c b/board/freescale/mx6q_sabreauto/mx6q_sabreauto.c index 135dff0..3190997 100644 --- a/board/freescale/mx6q_sabreauto/mx6q_sabreauto.c +++ b/board/freescale/mx6q_sabreauto/mx6q_sabreauto.c @@ -200,10 +200,10 @@ int board_eth_init(bd_t *bis) #ifdef CONFIG_CMD_MMC struct fsl_esdhc_cfg usdhc_cfg[4] = { - {USDHC1_BASE_ADDR, 1, 1}, - {USDHC2_BASE_ADDR, 1, 1}, - {USDHC3_BASE_ADDR, 1, 1}, - {USDHC4_BASE_ADDR, 1, 1}, + {USDHC1_BASE_ADDR, 1, 1, 1}, + {USDHC2_BASE_ADDR, 1, 1, 1}, + {USDHC3_BASE_ADDR, 1, 1, 1}, + {USDHC4_BASE_ADDR, 1, 1, 1}, }; #ifdef CONFIG_DYNAMIC_MMC_DEVNO @@ -301,6 +301,19 @@ int board_mmc_init(bd_t *bis) return -1; } +/* For DDR mode operation, provide target delay parameter for each SD port. + * Use cfg->esdhc_base to distinguish the SD port #. The delay for each port + * is dependent on trace lengths for that particular port. If the following + * CONFIG is not defined, then the default target delay value will be used. + */ +#ifdef CONFIG_GET_DDR_TARGET_DELAY +u32 get_ddr_delay(struct fsl_esdhc *cfg) +{ + /* No delay required on SABRE Auto board SD ports */ + return 0; +} +#endif + #endif int board_init(void) diff --git a/drivers/mmc/imx_esdhc.c b/drivers/mmc/imx_esdhc.c index a5345cb..d086949 100644 --- a/drivers/mmc/imx_esdhc.c +++ b/drivers/mmc/imx_esdhc.c @@ -325,6 +325,11 @@ void set_sysctl(struct mmc *mmc, uint clock) pre_div >>= 1; div -= 1; + /* for USDHC, pre_div requires another shift in DDR mode */ + if (cfg->is_usdhc && (mmc->bus_width == EMMC_MODE_4BIT_DDR || + mmc->bus_width == EMMC_MODE_8BIT_DDR)) + pre_div >>= 1; + clk = (pre_div << 8) | (div << 4); #ifndef CONFIG_IMX_ESDHC_V1 @@ -353,6 +358,16 @@ 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; + u32 target_delay = ESDHC_DLL_TARGET_DEFAULT_VAL; + +/* For DDR mode operation, provide target delay parameter for each SD port. + * Use cfg->esdhc_base to distinguish the SD port #. The delay for each port + * is dependent on trace lengths for that particular port. If the following + * CONFIG is not defined, then the default target delay value will be used. + */ +#ifdef CONFIG_GET_DDR_TARGET_DELAY + target_delay = get_ddr_delay(cfg); +#endif /* For i.MX50 TO1, need to force slave override mode */ if (get_board_rev() == (0x50000 | CHIP_REV_1_0) || @@ -367,6 +382,11 @@ static void esdhc_dll_setup(struct mmc *mmc) writel(dll_control, ®s->dllctrl); } else { + + /* on USDHC, enable DLL only for clock > 25 MHz */ + if (cfg->is_usdhc && mmc->clock <= 25000000) + return; + /* Disable auto clock gating for PERCLK, HCLK, and IPGCLK */ writel(readl(®s->sysctl) | 0x7, ®s->sysctl); /* Stop SDCLK while delay line is calibrated */ @@ -375,16 +395,29 @@ static void esdhc_dll_setup(struct mmc *mmc) /* Reset DLL */ writel(readl(®s->dllctrl) | 0x2, ®s->dllctrl); + dll_control = 0; + /* Enable DLL */ - writel(readl(®s->dllctrl) | 0x1, ®s->dllctrl); + if (cfg->is_usdhc) + dll_control |= 0x01000001; + else + dll_control |= 0x00000001; - dll_control = readl(®s->dllctrl); + writel(dll_control, ®s->dllctrl); /* Set target delay */ - dll_control &= ~ESDHC_DLLCTRL_TARGET_MASK; - dll_control |= (ESDHC_DLL_TARGET_DEFAULT_VAL << - ESDHC_DLLCTRL_TARGET_SHIFT); - writel(dll_control, ®s->dllctrl); + if (cfg->is_usdhc) { + dll_control &= ~USDHC_DLLCTRL_TARGET_MASK; + dll_control |= (((target_delay & USDHC_DLL_LOW_MASK) << + USDHC_DLLCTRL_TARGET_LOW_SHIFT) | + ((target_delay >> USDHC_DLL_HIGH_SHIFT) << + USDHC_DLLCTRL_TARGET_HIGH_SHIFT)); + writel(dll_control, ®s->dllctrl); + } else { + dll_control &= ~ESDHC_DLLCTRL_TARGET_MASK; + dll_control |= (target_delay << ESDHC_DLLCTRL_TARGET_SHIFT); + writel(dll_control, ®s->dllctrl); + } /* Wait for slave lock */ while ((readl(®s->dllstatus) & ESDHC_DLLSTS_SLV_LOCK_MASK) != @@ -478,7 +511,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) { struct fsl_esdhc *regs; struct mmc *mmc; - u32 ver, caps; + u32 caps; if (!cfg) return -1; @@ -497,9 +530,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) enable_usdhc(); #endif - ver = (readl(®s->hostver) & ESDHC_HOSTVER_VVN_MASK) - >> ESDHC_HOSTVER_VVN_SHIFT; - if (SDHC_IS_USDHC(ver)) + if (cfg->is_usdhc) sprintf(mmc->name, "FSL_USDHC"); caps = readl(®s->hostcapblt); @@ -517,7 +548,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) * it is to be used in SDR mode only. Use eSDHC for DDR mode. */ #ifndef CONFIG_MX50_ENABLE_USDHC_SDR - if (ver >= ESDHC_HOSTVER_DDR_SUPPORT) + if (cfg->is_usdhc) mmc->host_caps |= EMMC_MODE_4BIT_DDR; #ifdef CONFIG_EMMC_DDR_PORT_DETECT @@ -525,9 +556,6 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg) mmc->host_caps |= EMMC_MODE_4BIT_DDR; #endif - if (SDHC_IS_USDHC(ver)) - mmc->host_caps |= EMMC_MODE_4BIT_DDR; - #endif /* #ifndef CONFIG_MX50_ENABLE_USDHC_SDR */ mmc->f_min = 400000; diff --git a/include/asm-arm/arch-mx6/mx6_pins.h b/include/asm-arm/arch-mx6/mx6_pins.h index 2cc7114..f64473a 100644 --- a/include/asm-arm/arch-mx6/mx6_pins.h +++ b/include/asm-arm/arch-mx6/mx6_pins.h @@ -48,8 +48,8 @@ typedef enum iomux_config { PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) #define MX6Q_USDHC_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ - PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \ - PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) + PAD_CTL_PUS_47K_UP | PAD_CTL_SPEED_LOW | \ + PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) #define MX6Q_ENET_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \ diff --git a/include/configs/mx6q_sabreauto.h b/include/configs/mx6q_sabreauto.h index 34d53bc..32247c0 100644 --- a/include/configs/mx6q_sabreauto.h +++ b/include/configs/mx6q_sabreauto.h @@ -183,6 +183,8 @@ #define CONFIG_BOOT_PARTITION_ACCESS /* SD3 and SD4 are 8 bit */ #define CONFIG_MMC_8BIT_PORTS 0xC + /* Setup target delay in DDR mode for each SD port */ + #define CONFIG_GET_DDR_TARGET_DELAY #endif /* diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index 08e62a5..fe62c01 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -151,10 +151,8 @@ #define ESDHC_HOSTVER_VVN_MASK 0x0000ff00 #define ESDHC_HOSTVER_VVN_SHIFT 8 -#define ESDHC_HOSTVER_DDR_SUPPORT 0x13 -#define USDHC_HOSTVER_VVN 0x0 - -#define SDHC_IS_USDHC(x) (x == USDHC_HOSTVER_VVN) +#define ESDHC_HOSTVER_SVN_MASK 0x000000ff +#define ESDHC_HOSTVER_SVN_SHIFT 0 #define ESDHC_DLLCTRL_SLV_OVERRIDE_VAL 12 #define ESDHC_DLLCTRL_SLV_OVERRIDE_VAL_MASK 0x0000FC00 @@ -165,10 +163,20 @@ #define ESDHC_DLL_TARGET_DEFAULT_VAL 4 #define ESDHC_DLLSTS_SLV_LOCK_MASK 0x00000001 +#define USDHC_DLLCTRL_SLV_OVERRIDE_VAL_MASK 0x0000FE00 +#define USDHC_DLLCTRL_SLV_OVERRIDE_VAL_SHIFT 9 +#define USDHC_DLLCTRL_SLV_OVERRIDE 0x100 +#define USDHC_DLLCTRL_TARGET_MASK 0x00070078 +#define USDHC_DLLCTRL_TARGET_LOW_SHIFT 3 +#define USDHC_DLLCTRL_TARGET_HIGH_SHIFT 16 +#define USDHC_DLL_LOW_MASK 0xF +#define USDHC_DLL_HIGH_SHIFT 4 + struct fsl_esdhc_cfg { u32 esdhc_base; u32 no_snoop; u32 clk_enable; + u32 is_usdhc; }; #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_IMX_MMC) -- cgit v1.1