
Hi Peng,
-----Original Message----- From: Peng Fan peng.fan@nxp.com Sent: Monday, July 20, 2020 9:42 AM To: Y.b. Lu yangbo.lu@nxp.com; u-boot@lists.denx.de; Priyanka Jain priyanka.jain@nxp.com; 'Jaehoon Chung' jh80.chung@samsung.com Cc: Y.b. Lu yangbo.lu@nxp.com Subject: RE: [v2, 07/11] mmc: fsl_esdhc: support eMMC HS400 mode
Subject: [v2, 07/11] mmc: fsl_esdhc: support eMMC HS400 mode
The process for eMMC HS400 mode for eSDHC is,
- Perform the Tuning Process at the HS400 target operating frequency. Latched the clock division value.
- if read transaction, then set the SDTIMNGCTL[FLW_CTL_BG].
- Switch to High Speed mode and then set the card clock frequency to a value not greater than 52Mhz
- Clear TBCTL[TB_EN],tuning block enable bit.
- Change to 8 bit DDR Mode
- Switch the card to HS400 mode.
- Set TBCTL[TB_EN], tuning block enable bit.
- Clear SYSCTL[SDCLKEN]
- Wait for PRSSTAT[SDSTB] to be set
- Change the clock division to latched value.Set TBCTL[HS 400 mode] and Set SDCLKCTL[CMD_CLK_CTRL]
- Set SYSCTL[SDCLKEN]
- Wait for PRSSTAT[SDSTB] to be set
- Set DLLCFG0[DLL_ENABLE] and DLLCFG0[DLL_FREQ_SEL].
- Wait for delay chain to lock.
- Set TBCTL[HS400_WNDW_ADJUST]
- Again clear SYSCTL[SDCLKEN]
- Wait for PRSSTAT[SDSTB] to be set
- Set ESDHCCTL[FAF]
- Wait for ESDHCCTL[FAF] to be cleared 20. Set SYSCTL[SDCLKEN] 21. Wait
for PRSSTAT[SDSTB] to be set.
Signed-off-by: Yangbo Lu yangbo.lu@nxp.com
Changes for v2:
- None.
drivers/mmc/fsl_esdhc.c | 98 ++++++++++++++++++++++++++++++++----------------- include/fsl_esdhc.h | 12 ++++++ 2 files changed, 76 insertions(+), 34 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 607b420..c1a127c 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -62,7 +62,12 @@ struct fsl_esdhc { uint hostcapblt2; /* Host controller capabilities register 2 */ char reserved6[8]; /* reserved */ uint tbctl; /* Tuning block control register */
- char reserved7[744]; /* reserved */
- char reserved7[32]; /* reserved */
- uint sdclkctl; /* SD clock control register */
- uint sdtimingctl; /* SD timing control register */
- char reserved8[20]; /* reserved */
- uint dllcfg0; /* DLL config 0 register */
- char reserved9[680]; /* reserved */ uint esdhcctl; /* eSDHC control register */
};
@@ -568,6 +573,38 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) } }
+static void esdhc_flush_async_fifo(struct fsl_esdhc_priv *priv) {
- struct fsl_esdhc *regs = priv->esdhc_regs;
- u32 time_out;
- esdhc_setbits32(®s->esdhcctl, ESDHCCTL_FAF);
- time_out = 20;
- while (esdhc_read32(®s->esdhcctl) & ESDHCCTL_FAF) {
if (time_out == 0) {
printf("fsl_esdhc: Flush asynchronous FIFO timeout.\n");
break;
}
time_out--;
mdelay(1);
- }
+}
+static void esdhc_tuning_block_enable(struct fsl_esdhc_priv *priv,
bool en)
+{
- struct fsl_esdhc *regs = priv->esdhc_regs;
- esdhc_clock_control(priv, false);
- esdhc_flush_async_fifo(priv);
- if (en)
esdhc_setbits32(®s->tbctl, TBCTL_TB_EN);
- else
esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN);
- esdhc_clock_control(priv, true);
+}
static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) { struct fsl_esdhc *regs = priv->esdhc_regs; @@ -577,7 +614,17 @@ static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) if (mode == MMC_HS_200) esdhc_clrsetbits32(®s->autoc12err, UHSM_MASK, UHSM_SDR104_HS200);
if (mode == MMC_HS_400) {
esdhc_setbits32(®s->tbctl, HS400_MODE);
esdhc_setbits32(®s->sdclkctl, CMD_CLK_CTL);
esdhc_clock_control(priv, true);
esdhc_setbits32(®s->dllcfg0, DLL_ENABLE | DLL_FREQ_SEL);
esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST);
esdhc_clock_control(priv, false);
esdhc_flush_async_fifo(priv);
} esdhc_clock_control(priv, true);
}
@@ -592,6 +639,9 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) esdhc_clock_control(priv, true); }
- if (mmc->selected_mode == MMC_HS_400)
esdhc_tuning_block_enable(priv, true);
- /* Set the clock speed */ if (priv->clock != mmc->clock) set_sysctl(priv, mmc, mmc->clock);
@@ -987,38 +1037,6 @@ static int fsl_esdhc_reinit(struct udevice *dev) }
#ifdef MMC_SUPPORTS_TUNING -static void esdhc_flush_async_fifo(struct fsl_esdhc_priv *priv) -{
- struct fsl_esdhc *regs = priv->esdhc_regs;
- u32 time_out;
- esdhc_setbits32(®s->esdhcctl, ESDHCCTL_FAF);
- time_out = 20;
- while (esdhc_read32(®s->esdhcctl) & ESDHCCTL_FAF) {
if (time_out == 0) {
printf("fsl_esdhc: Flush asynchronous FIFO timeout.\n");
break;
}
time_out--;
mdelay(1);
- }
-}
-static void esdhc_tuning_block_enable(struct fsl_esdhc_priv *priv,
bool en)
-{
- struct fsl_esdhc *regs = priv->esdhc_regs;
- esdhc_clock_control(priv, false);
- esdhc_flush_async_fifo(priv);
- if (en)
esdhc_setbits32(®s->tbctl, TBCTL_TB_EN);
- else
esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN);
- esdhc_clock_control(priv, true);
-}
static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
{
struct fsl_esdhc_plat *plat = dev_get_platdata(dev); @@ -1046,8 +1064,11 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode)
esdhc_write32(®s->irqstaten, irqstaten);
- if (i != MAX_TUNING_LOOP)
- if (i != MAX_TUNING_LOOP) {
if (plat->mmc.hs400_tuning)
Ok, it is used here, but I not see the benefit putting hs400_tunning into common mmc structure.
Do you have any suggestion if we don't use a flag to identify HS400 and HS200 tuning in common mmc structure? Thanks.
Regards, Peng.
esdhc_setbits32(®s->sdtimingctl, FLW_CTL_BG);
return 0;
}
printf("fsl_esdhc: tuning failed!\n"); esdhc_clrbits32(®s->autoc12err, SMPCLKSEL); @@ -1057,6 +1078,14
@@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) } #endif
+int fsl_esdhc_hs400_prepare_ddr(struct udevice *dev) {
- struct fsl_esdhc_priv *priv = dev_get_priv(dev);
- esdhc_tuning_block_enable(priv, false);
- return 0;
+}
static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1065,6 +1094,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops =
{
.execute_tuning = fsl_esdhc_execute_tuning, #endif .reinit = fsl_esdhc_reinit,
- .hs400_prepare_ddr = fsl_esdhc_hs400_prepare_ddr,
};
static const struct udevice_id fsl_esdhc_ids[] = { diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index ada95bc..cbb2c34 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -176,6 +176,18 @@
/* Tuning block control register */ #define TBCTL_TB_EN 0x00000004 +#define HS400_MODE 0x00000010 +#define HS400_WNDW_ADJUST 0x00000040
+/* SD clock control register */ +#define CMD_CLK_CTL 0x00008000
+/* SD timing control register */ +#define FLW_CTL_BG 0x00008000
+/* DLL config 0 register */ +#define DLL_ENABLE 0x80000000 +#define DLL_FREQ_SEL 0x08000000
#define MAX_TUNING_LOOP 40
-- 2.7.4