> 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(&regs->esdhcctl, ESDHCCTL_FAF);
> +
> +     time_out = 20;
> +     while (esdhc_read32(&regs->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(&regs->tbctl, TBCTL_TB_EN);
> +     else
> +             esdhc_clrbits32(&regs->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(&regs->autoc12err, UHSM_MASK,
>                                  UHSM_SDR104_HS200);
> +     if (mode == MMC_HS_400) {
> +             esdhc_setbits32(&regs->tbctl, HS400_MODE);
> +             esdhc_setbits32(&regs->sdclkctl, CMD_CLK_CTL);
> +             esdhc_clock_control(priv, true);
> 
> +             esdhc_setbits32(&regs->dllcfg0, DLL_ENABLE | DLL_FREQ_SEL);
> +             esdhc_setbits32(&regs->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(&regs->esdhcctl, ESDHCCTL_FAF);
> -
> -     time_out = 20;
> -     while (esdhc_read32(&regs->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(&regs->tbctl, TBCTL_TB_EN);
> -     else
> -             esdhc_clrbits32(&regs->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(&regs->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(&regs->sdtimingctl, FLW_CTL_BG);
>               return 0;
> +     }
> 
>       printf("fsl_esdhc: tuning failed!\n");
>       esdhc_clrbits32(&regs->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

Reply via email to