Hi Peng, > -----Original Message----- > From: Peng Fan <peng....@nxp.com> > Sent: Monday, July 20, 2020 9:42 AM > To: Y.b. Lu <yangbo...@nxp.com>; u-boot@lists.denx.de; Priyanka Jain > <priyanka.j...@nxp.com>; 'Jaehoon Chung' <jh80.ch...@samsung.com> > Cc: Y.b. Lu <yangbo...@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, > > > > 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.
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