> Subject: [v2, 07/11] mmc: fsl_esdhc: support eMMC HS400 mode > > The process for eMMC HS400 mode for eSDHC is, > > 1. Perform the Tuning Process at the HS400 target operating frequency. > Latched the clock division value. > 2. if read transaction, then set the SDTIMNGCTL[FLW_CTL_BG]. > 3. Switch to High Speed mode and then set the card clock frequency to > a value not greater than 52Mhz > 4. Clear TBCTL[TB_EN],tuning block enable bit. > 5. Change to 8 bit DDR Mode > 6. Switch the card to HS400 mode. > 7. Set TBCTL[TB_EN], tuning block enable bit. > 8. Clear SYSCTL[SDCLKEN] > 9. Wait for PRSSTAT[SDSTB] to be set > 10. Change the clock division to latched value.Set TBCTL[HS 400 mode] > and Set SDCLKCTL[CMD_CLK_CTRL] > 11. Set SYSCTL[SDCLKEN] > 12. Wait for PRSSTAT[SDSTB] to be set > 13. Set DLLCFG0[DLL_ENABLE] and DLLCFG0[DLL_FREQ_SEL]. > 14. Wait for delay chain to lock. > 15. Set TBCTL[HS400_WNDW_ADJUST] > 16. Again clear SYSCTL[SDCLKEN] > 17. Wait for PRSSTAT[SDSTB] to be set > 18. Set ESDHCCTL[FAF] > 19. 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...@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. 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