From 390f9bddb9c84f75649024b41b8cf2a766379ce0 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:57:59 +0800 Subject: mmc: add a reinit() API For DM_MMC, the controller re-initialization is needed to clear old configuration for mmc rescan. Signed-off-by: Yangbo Lu Reviewed-by: Jaehoon Chung --- drivers/mmc/mmc-uclass.c | 15 +++++++++++++++ drivers/mmc/mmc.c | 8 ++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 90690c8d1e3..b90e1ee30d1 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -171,6 +171,21 @@ int mmc_deferred_probe(struct mmc *mmc) return dm_mmc_deferred_probe(mmc->dev); } +int dm_mmc_reinit(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->reinit) + return ops->reinit(dev); + + return 0; +} + +int mmc_reinit(struct mmc *mmc) +{ + return dm_mmc_reinit(mmc->dev); +} + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d79cdef62ed..07275053046 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2816,13 +2816,17 @@ int mmc_get_op_cond(struct mmc *mmc) return err; #if CONFIG_IS_ENABLED(DM_MMC) - /* The device has already been probed ready for use */ + /* + * Re-initialization is needed to clear old configuration for + * mmc rescan. + */ + err = mmc_reinit(mmc); #else /* made sure it's not NULL earlier */ err = mmc->cfg->ops->init(mmc); +#endif if (err) return err; -#endif mmc->ddr_mode = 0; retry: -- cgit v1.2.3 From 1fdefd1d0d12ac728e29a67a224777299840a397 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:00 +0800 Subject: mmc: fsl_esdhc: add a reinit() callback Add a reinit() callback for mmc rescan. Signed-off-by: Yangbo Lu Reviewed-by: Jaehoon Chung --- drivers/mmc/fsl_esdhc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index de9fe01bc5c..83feaf192b1 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -907,6 +907,14 @@ static int fsl_esdhc_set_ios(struct udevice *dev) return esdhc_set_ios_common(priv, &plat->mmc); } +static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_platdata(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + return esdhc_init_common(priv, &plat->mmc); +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -914,6 +922,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = fsl_esdhc_execute_tuning, #endif + .reinit = fsl_esdhc_reinit, }; static const struct udevice_id fsl_esdhc_ids[] = { -- cgit v1.2.3 From b1a4247b411522bc4b81dd349c5945dea0b3e9f8 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:01 +0800 Subject: mmc: fsl_esdhc: support tuning for eMMC HS200 Support tuning process for eMMC HS200 for eSDHC. Signed-off-by: Yangbo Lu --- drivers/mmc/fsl_esdhc.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 83feaf192b1..4e04c101dc9 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -60,7 +60,9 @@ struct fsl_esdhc { uint dmaerrattr; /* DMA error attribute register */ char reserved5[4]; /* reserved */ uint hostcapblt2; /* Host controller capabilities register 2 */ - char reserved6[756]; /* reserved */ + char reserved6[8]; /* reserved */ + uint tbctl; /* Tuning block control register */ + char reserved7[744]; /* reserved */ uint esdhcctl; /* eSDHC control register */ }; @@ -101,7 +103,9 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) if (data) { xfertyp |= XFERTYP_DPSEL; #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - xfertyp |= XFERTYP_DMAEN; + if (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK && + cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200) + xfertyp |= XFERTYP_DMAEN; #endif if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; @@ -380,6 +384,10 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_write32(®s->cmdarg, cmd->cmdarg); esdhc_write32(®s->xfertyp, xfertyp); + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + flags = IRQSTAT_BRR; + /* Wait for the command to complete */ start = get_timer(0); while (!(esdhc_read32(®s->irqstat) & flags)) { @@ -439,6 +447,11 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO esdhc_pio_read_write(priv, data); #else + flags = DATA_COMPLETE; + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + flags = IRQSTAT_BRR; + do { irqstat = esdhc_read32(®s->irqstat); @@ -451,7 +464,7 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = -ECOMM; goto out; } - } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); + } while ((irqstat & flags) != flags); /* * Need invalidate the dcache here again to avoid any @@ -555,6 +568,19 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) } } +static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + + esdhc_clock_control(priv, false); + + if (mode == MMC_HS_200) + esdhc_clrsetbits32(®s->autoc12err, UHSM_MASK, + UHSM_SDR104_HS200); + + esdhc_clock_control(priv, true); +} + static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) { struct fsl_esdhc *regs = priv->esdhc_regs; @@ -570,6 +596,9 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) if (priv->clock != mmc->clock) set_sysctl(priv, mmc, mmc->clock); + /* Set timing */ + esdhc_set_timing(priv, mmc->selected_mode); + /* Set the bus width */ esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8); @@ -915,6 +944,77 @@ static int fsl_esdhc_reinit(struct udevice *dev) return esdhc_init_common(priv, &plat->mmc); } +#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); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + struct fsl_esdhc *regs = priv->esdhc_regs; + u32 val, irqstaten; + int i; + + esdhc_tuning_block_enable(priv, true); + esdhc_setbits32(®s->autoc12err, EXECUTE_TUNING); + + irqstaten = esdhc_read32(®s->irqstaten); + esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); + + for (i = 0; i < MAX_TUNING_LOOP; i++) { + mmc_send_tuning(&plat->mmc, opcode, NULL); + mdelay(1); + + val = esdhc_read32(®s->autoc12err); + if (!(val & EXECUTE_TUNING)) { + if (val & SMPCLKSEL) + break; + } + } + + esdhc_write32(®s->irqstaten, irqstaten); + + if (i != MAX_TUNING_LOOP) + return 0; + + printf("fsl_esdhc: tuning failed!\n"); + esdhc_clrbits32(®s->autoc12err, SMPCLKSEL); + esdhc_clrbits32(®s->autoc12err, EXECUTE_TUNING); + esdhc_tuning_block_enable(priv, false); + return -ETIMEDOUT; +} +#endif + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, -- cgit v1.2.3 From 1b5f0ba7a5e880869069b9b6ea4c0244118a05af Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:02 +0800 Subject: mmc: fsl_esdhc: clean TBCTL[TB_EN] manually during init Clean TBCTL[TB_EN] manually during init since it is not able to be reset by reset all operation. Signed-off-by: Yangbo Lu --- drivers/mmc/fsl_esdhc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 4e04c101dc9..e7db55d881a 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -637,6 +637,9 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) return -ETIMEDOUT; } + /* Clean TBCTL[TB_EN] which is not able to be reset by reset all */ + esdhc_clrbits32(®s->tbctl, TBCTL_TB_EN); + esdhc_enable_cache_snooping(regs); esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); -- cgit v1.2.3 From 8c96880814b23b5e17b5e7d350ea6066dae54bc6 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:03 +0800 Subject: mmc: add a hs400_tuning flag Some controllers may have difference between HS200 tuning and HS400 tuning, such as different registers setting, different procedure, or different errata. This patch is to add a hs400_tuning flag to identify the tuning for HS400 mode. Signed-off-by: Yangbo Lu --- drivers/mmc/mmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 07275053046..b75c2bc830a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1982,7 +1982,9 @@ static int mmc_select_hs400(struct mmc *mmc) mmc_set_clock(mmc, mmc->tran_speed, false); /* execute tuning if needed */ + mmc->hs400_tuning = 1; err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); + mmc->hs400_tuning = 0; if (err) { debug("tuning failed\n"); return err; -- cgit v1.2.3 From d271e10581e7f15451e9d4c3cdd39044440a848a Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:04 +0800 Subject: mmc: add a mmc_hs400_prepare_ddr() interface Add a mmc_hs400_prepare_ddr() interface for controllers which needs preparation before switching to DDR mode for HS400 mode. Signed-off-by: Yangbo Lu --- drivers/mmc/mmc-uclass.c | 15 +++++++++++++++ drivers/mmc/mmc.c | 4 ++++ 2 files changed, 19 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index b90e1ee30d1..ec59bcd8566 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -142,6 +142,21 @@ int mmc_set_enhanced_strobe(struct mmc *mmc) } #endif +int dm_mmc_hs400_prepare_ddr(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->hs400_prepare_ddr) + return ops->hs400_prepare_ddr(dev); + + return 0; +} + +int mmc_hs400_prepare_ddr(struct mmc *mmc) +{ + return dm_mmc_hs400_prepare_ddr(mmc->dev); +} + int dm_mmc_host_power_cycle(struct udevice *dev) { struct dm_mmc_ops *ops = mmc_get_ops(dev); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b75c2bc830a..8502503d361 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1993,6 +1993,10 @@ static int mmc_select_hs400(struct mmc *mmc) /* Set back to HS */ mmc_set_card_speed(mmc, MMC_HS, true); + err = mmc_hs400_prepare_ddr(mmc); + if (err) + return err; + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG); if (err) -- cgit v1.2.3 From db8f93672b42411856b11cf294a6f9c25482179c Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:05 +0800 Subject: 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 --- drivers/mmc/fsl_esdhc.c | 120 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 34 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index e7db55d881a..c53751d0bbb 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,16 +573,80 @@ 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_exit_hs400(struct fsl_esdhc_priv *priv) +{ + struct fsl_esdhc *regs = priv->esdhc_regs; + + esdhc_clrbits32(®s->sdtimingctl, FLW_CTL_BG); + esdhc_clrbits32(®s->sdclkctl, CMD_CLK_CTL); + + esdhc_clock_control(priv, false); + esdhc_clrbits32(®s->tbctl, HS400_MODE); + esdhc_clock_control(priv, true); + + esdhc_clrbits32(®s->dllcfg0, DLL_FREQ_SEL | DLL_ENABLE); + esdhc_clrbits32(®s->tbctl, HS400_WNDW_ADJUST); + + esdhc_tuning_block_enable(priv, false); +} + static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) { struct fsl_esdhc *regs = priv->esdhc_regs; + /* Exit HS400 mode before setting any other mode */ + if (esdhc_read32(®s->tbctl) & HS400_MODE && + mode != MMC_HS_400) + esdhc_exit_hs400(priv); + esdhc_clock_control(priv, false); 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 +661,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); @@ -948,38 +1020,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); @@ -1007,8 +1047,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) + esdhc_setbits32(®s->sdtimingctl, FLW_CTL_BG); return 0; + } printf("fsl_esdhc: tuning failed!\n"); esdhc_clrbits32(®s->autoc12err, SMPCLKSEL); @@ -1018,6 +1061,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, @@ -1026,6 +1077,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[] = { -- cgit v1.2.3 From 30f6444d024a74ee48aa6969c1531aecd3c59deb Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:06 +0800 Subject: mmc: fsl_esdhc: fix mmc->clock with actual clock Fix mmc->clock with actual clock which is divided by the controller, and record it with priv->clock which was removed accidentally. Signed-off-by: Yangbo Lu --- drivers/mmc/fsl_esdhc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index c53751d0bbb..ce87416f5d9 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -523,6 +523,9 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) while (sdhc_clk / (div * pre_div) > clock && div < 16) div++; + mmc->clock = sdhc_clk / pre_div / div; + priv->clock = mmc->clock; + pre_div >>= 1; div -= 1; -- cgit v1.2.3 From 78804de483c4d59d4e23acf8c9fb56eee07fb427 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 1 Sep 2020 16:58:07 +0800 Subject: mmc: fsl_esdhc: fix eMMC HS400 stability issue There was a fix-up for eMMC HS400 stability issue in Linux. Patch link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=58d0bf843b49fa99588ac9f85178bd8dfd651b53 Description: Currently only LX2160A eSDHC supports eMMC HS400. According to a large number of tests, eMMC HS400 failed to work at 150MHz, and for a few boards failed to work at 175MHz. But eMMC HS400 worked fine on 200MHz. We hadn't found the root cause but setting eSDHC_DLLCFG0[DLL_FREQ_SEL] = 0 using slow delay chain seemed to resovle this issue. Let's use this as fixup for now. Introduce the fix-up in u-boot since the issue could be reproduced in u-boot too. Signed-off-by: Yangbo Lu --- drivers/mmc/fsl_esdhc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index ce87416f5d9..a6092ad26fb 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -644,7 +644,10 @@ static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode) esdhc_setbits32(®s->sdclkctl, CMD_CLK_CTL); esdhc_clock_control(priv, true); - esdhc_setbits32(®s->dllcfg0, DLL_ENABLE | DLL_FREQ_SEL); + if (priv->clock == 200000000) + esdhc_setbits32(®s->dllcfg0, DLL_FREQ_SEL); + + esdhc_setbits32(®s->dllcfg0, DLL_ENABLE); esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST); esdhc_clock_control(priv, false); -- cgit v1.2.3 From ef5ab0d13a7a44469f6c765c8acc8d54c23213de Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 22 Sep 2020 18:11:42 +0800 Subject: mmc: do not send cmd13 if the parameter 'send_status' is 0 for __mmc_switch According to the code logic in __mmc_switch, if the parameter 'send_status' is zero, no need to send cmd13, just wait the stated timeout time, then can return directly. Signed-off-by: Haibo Chen --- drivers/mmc/mmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 8502503d361..7783535d095 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -805,8 +805,10 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, * capable of polling by using mmc_wait_dat0, then rely on waiting the * stated timeout to be sufficient. */ - if (ret == -ENOSYS && !send_status) + if (ret == -ENOSYS && !send_status) { mdelay(timeout_ms); + return 0; + } /* Finally wait until the card is ready or indicates a failure * to switch. It doesn't hurt to use CMD13 here even if send_status -- cgit v1.2.3 From 9098682200e6cca4b776638a51200dafa16f50fb Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 22 Sep 2020 18:11:43 +0800 Subject: mmc: fsl_esdhc_imx: remove the 1ms delay before sending command This 1ms delay before sending command already exist from the beginning of the fsl_esdhc driver added in year 2008. Now this driver has been split for two files: fsl_esdhc.c and fsl_esdhc_imx.c. fsl_esdhc_imx.c only for i.MX series. i.MX series esdhc/usdhc do not need this 1ms delay before sending any command. So remove this 1ms, this will save a lot time if handling a large mmc data. Signed-off-by: Haibo Chen --- drivers/mmc/fsl_esdhc_imx.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 0c866b168f9..caaef0b7da6 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -462,13 +462,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) ; - /* Wait at least 8 SD clock cycles before the next command */ - /* - * Note: This is way more than 8 cycles, but 1ms seems to - * resolve timing issues with some cards - */ - udelay(1000); - /* Set up for a data transfer if we have one */ if (data) { err = esdhc_setup_data(priv, mmc, data); -- cgit v1.2.3 From da86e8cfcb03ed5c1d8e0718bc8bc8583e60ced8 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 23 Sep 2020 12:42:47 +0200 Subject: mmc: fsl_esdhc: simplify 64bit check for SDMA transfers SDMA can only do DMA with 32 bit addresses. This is true for all architectures (just doesn't apply to 32 bit ones). Simplify the code and remove unnecessary CONFIG_FSL_LAYERSCAPE. Also make the error message more concise. Signed-off-by: Michael Walle --- drivers/mmc/fsl_esdhc.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index a6092ad26fb..041f7d3ebc9 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -211,9 +211,7 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, { int timeout; struct fsl_esdhc *regs = priv->esdhc_regs; -#if defined(CONFIG_FSL_LAYERSCAPE) dma_addr_t addr; -#endif uint wml_value; wml_value = data->blocksize/4; @@ -224,15 +222,10 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#if defined(CONFIG_FSL_LAYERSCAPE) addr = virt_to_phys((void *)(data->dest)); if (upper_32_bits(addr)) - printf("Error found for upper 32 bits\n"); - else - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); -#else - esdhc_write32(®s->dsaddr, (u32)data->dest); -#endif + printf("Cannot use 64 bit addresses with SDMA\n"); + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); #endif } else { #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO @@ -251,15 +244,10 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO -#if defined(CONFIG_FSL_LAYERSCAPE) addr = virt_to_phys((void *)(data->src)); if (upper_32_bits(addr)) - printf("Error found for upper 32 bits\n"); - else - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); -#else - esdhc_write32(®s->dsaddr, (u32)data->src); -#endif + printf("Cannot use 64 bit addresses with SDMA\n"); + esdhc_write32(®s->dsaddr, lower_32_bits(addr)); #endif } @@ -316,17 +304,12 @@ static void check_and_invalidate_dcache_range unsigned end = 0; unsigned size = roundup(ARCH_DMA_MINALIGN, data->blocks*data->blocksize); -#if defined(CONFIG_FSL_LAYERSCAPE) dma_addr_t addr; addr = virt_to_phys((void *)(data->dest)); if (upper_32_bits(addr)) - printf("Error found for upper 32 bits\n"); - else - start = lower_32_bits(addr); -#else - start = (unsigned)data->dest; -#endif + printf("Cannot use 64 bit addresses with SDMA\n"); + start = lower_32_bits(addr); end = start + size; invalidate_dcache_range(start, end); } -- cgit v1.2.3 From b1ba1460a445bcc67972a617625d0349e4f22b31 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 23 Sep 2020 12:42:48 +0200 Subject: mmc: fsl_esdhc: use dma-mapping API Use the dma_{map,unmap}_single() calls. These will take care of the flushing and invalidation of caches. Signed-off-by: Michael Walle --- drivers/mmc/fsl_esdhc.c | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 041f7d3ebc9..1b20b4360fa 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -26,6 +26,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -98,6 +99,7 @@ struct fsl_esdhc_priv { struct mmc *mmc; #endif struct udevice *dev; + dma_addr_t dma_addr; }; /* Return the XFERTYP flags for a given command and data packet */ @@ -210,8 +212,8 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, struct mmc_data *data) { int timeout; + uint trans_bytes = data->blocksize * data->blocks; struct fsl_esdhc *regs = priv->esdhc_regs; - dma_addr_t addr; uint wml_value; wml_value = data->blocksize/4; @@ -222,17 +224,13 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - addr = virt_to_phys((void *)(data->dest)); - if (upper_32_bits(addr)) + priv->dma_addr = dma_map_single(data->dest, trans_bytes, + mmc_get_dma_dir(data)); + if (upper_32_bits(priv->dma_addr)) printf("Cannot use 64 bit addresses with SDMA\n"); - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); + esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); #endif } else { -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - flush_dcache_range((ulong)data->src, - (ulong)data->src+data->blocks - *data->blocksize); -#endif if (wml_value > WML_WR_WML_MAX) wml_value = WML_WR_WML_MAX_VAL; @@ -244,10 +242,11 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, wml_value << 16); #ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - addr = virt_to_phys((void *)(data->src)); - if (upper_32_bits(addr)) + priv->dma_addr = dma_map_single((void *)data->src, trans_bytes, + mmc_get_dma_dir(data)); + if (upper_32_bits(priv->dma_addr)) printf("Cannot use 64 bit addresses with SDMA\n"); - esdhc_write32(®s->dsaddr, lower_32_bits(addr)); + esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); #endif } @@ -297,23 +296,6 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, return 0; } -static void check_and_invalidate_dcache_range - (struct mmc_cmd *cmd, - struct mmc_data *data) { - unsigned start = 0; - unsigned end = 0; - unsigned size = roundup(ARCH_DMA_MINALIGN, - data->blocks*data->blocksize); - dma_addr_t addr; - - addr = virt_to_phys((void *)(data->dest)); - if (upper_32_bits(addr)) - printf("Cannot use 64 bit addresses with SDMA\n"); - start = lower_32_bits(addr); - end = start + size; - invalidate_dcache_range(start, end); -} - /* * Sends a command out on the bus. Takes the mmc pointer, * a command pointer, and an optional data pointer. @@ -357,9 +339,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, err = esdhc_setup_data(priv, mmc, data); if(err) return err; - - if (data->flags & MMC_DATA_READ) - check_and_invalidate_dcache_range(cmd, data); } /* Figure out the transfer arguments */ @@ -459,9 +438,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, * cache-fill during the DMA operations such as the * speculative pre-fetching etc. */ - if (data->flags & MMC_DATA_READ) { - check_and_invalidate_dcache_range(cmd, data); - } + dma_unmap_single(priv->dma_addr, + data->blocks * data->blocksize, + mmc_get_dma_dir(data)); #endif } -- cgit v1.2.3 From 7e48a028a42c111ba38a90b86e5f57dace980fa0 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 23 Sep 2020 12:42:49 +0200 Subject: mmc: fsl_esdhc: simplify esdhc_setup_data() First, we need the waterlevel setting for PIO mode only. Secondy, both DMA setup code is identical for both directions, except for the data pointer. Thus, unify them. Signed-off-by: Michael Walle --- drivers/mmc/fsl_esdhc.c | 69 ++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 27 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 1b20b4360fa..10a699f692b 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -208,49 +208,64 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, } #endif -static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, - struct mmc_data *data) +#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO +static void esdhc_setup_watermark_level(struct fsl_esdhc_priv *priv, + struct mmc_data *data) { - int timeout; - uint trans_bytes = data->blocksize * data->blocks; struct fsl_esdhc *regs = priv->esdhc_regs; - uint wml_value; - - wml_value = data->blocksize/4; + uint wml_value = data->blocksize / 4; if (data->flags & MMC_DATA_READ) { if (wml_value > WML_RD_WML_MAX) wml_value = WML_RD_WML_MAX_VAL; esdhc_clrsetbits32(®s->wml, WML_RD_WML_MASK, wml_value); -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - priv->dma_addr = dma_map_single(data->dest, trans_bytes, - mmc_get_dma_dir(data)); - if (upper_32_bits(priv->dma_addr)) - printf("Cannot use 64 bit addresses with SDMA\n"); - esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); -#endif } else { if (wml_value > WML_WR_WML_MAX) wml_value = WML_WR_WML_MAX_VAL; - if (!(esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL)) { - printf("Can not write to locked SD card.\n"); - return -EINVAL; - } - esdhc_clrsetbits32(®s->wml, WML_WR_WML_MASK, - wml_value << 16); -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - priv->dma_addr = dma_map_single((void *)data->src, trans_bytes, - mmc_get_dma_dir(data)); - if (upper_32_bits(priv->dma_addr)) - printf("Cannot use 64 bit addresses with SDMA\n"); - esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); -#endif + wml_value << 16); } +} +#endif + +static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data) +{ + uint trans_bytes = data->blocksize * data->blocks; + struct fsl_esdhc *regs = priv->esdhc_regs; + void *buf; + + if (data->flags & MMC_DATA_WRITE) + buf = (void *)data->src; + else + buf = data->dest; + priv->dma_addr = dma_map_single(buf, trans_bytes, + mmc_get_dma_dir(data)); + if (upper_32_bits(priv->dma_addr)) + printf("Cannot use 64 bit addresses with SDMA\n"); + esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); +} + +static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, + struct mmc_data *data) +{ + int timeout; + bool is_write = data->flags & MMC_DATA_WRITE; + struct fsl_esdhc *regs = priv->esdhc_regs; + + if (is_write && !(esdhc_read32(®s->prsstat) & PRSSTAT_WPSPL)) { + printf("Can not write to locked SD card.\n"); + return -EINVAL; + } + +#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO + esdhc_setup_watermark_level(priv, data); +#else + esdhc_setup_dma(priv, data); +#endif /* Calculate the timeout period for data transactions */ /* -- cgit v1.2.3 From 4d6a773b1cfcb7e62d12dd31e588b5d00179b470 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 23 Sep 2020 12:42:51 +0200 Subject: mmc: sdhci: move the ADMA2 table handling into own module There are other (non-SDHCI) controllers which supports ADMA2 descriptor tables, namely the Freescale eSDHC. Instead of copying the code, move it into an own module. Signed-off-by: Michael Walle --- drivers/mmc/Kconfig | 5 ++++ drivers/mmc/Makefile | 1 + drivers/mmc/sdhci-adma.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/sdhci.c | 63 ++++++----------------------------------- 4 files changed, 87 insertions(+), 55 deletions(-) create mode 100644 drivers/mmc/sdhci-adma.c (limited to 'drivers/mmc') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 0c252e34c74..88582db58c9 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,9 @@ config SPL_DM_MMC if MMC +config MMC_SDHCI_ADMA_HELPERS + bool + config MMC_SPI bool "Support for SPI-based MMC controller" depends on DM_MMC && DM_SPI @@ -445,6 +448,7 @@ config MMC_SDHCI_SDMA config MMC_SDHCI_ADMA bool "Support SDHCI ADMA2" depends on MMC_SDHCI + select MMC_SDHCI_ADMA_HELPERS help This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 @@ -452,6 +456,7 @@ config MMC_SDHCI_ADMA config SPL_MMC_SDHCI_ADMA bool "Support SDHCI ADMA2 in SPL" depends on MMC_SDHCI + select MMC_SDHCI_ADMA_HELPERS help This enables support for the ADMA (Advanced DMA) defined in the SD Host Controller Standard Specification Version 3.00 in SPL. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 22266ec8ece..1c849cbab2f 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -6,6 +6,7 @@ obj-y += mmc.o obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o obj-$(CONFIG_$(SPL_)MMC_WRITE) += mmc_write.o +obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o ifndef CONFIG_$(SPL_)BLK obj-y += mmc_legacy.o diff --git a/drivers/mmc/sdhci-adma.c b/drivers/mmc/sdhci-adma.c new file mode 100644 index 00000000000..2ec057fbb19 --- /dev/null +++ b/drivers/mmc/sdhci-adma.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SDHCI ADMA2 helper functions. + */ + +#include +#include +#include +#include +#include + +static void sdhci_adma_desc(struct sdhci_adma_desc *desc, + dma_addr_t addr, u16 len, bool end) +{ + u8 attr; + + attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + if (end) + attr |= ADMA_DESC_ATTR_END; + + desc->attr = attr; + desc->len = len; + desc->reserved = 0; + desc->addr_lo = lower_32_bits(addr); +#ifdef CONFIG_DMA_ADDR_T_64BIT + desc->addr_hi = upper_32_bits(addr); +#endif +} + +/** + * sdhci_prepare_adma_table() - Populate the ADMA table + * + * @table: Pointer to the ADMA table + * @data: Pointer to MMC data + * @addr: DMA address to write to or read from + * + * Fill the ADMA table according to the MMC data to read from or write to the + * given DMA address. + * Please note, that the table size depends on CONFIG_SYS_MMC_MAX_BLK_COUNT and + * we don't have to check for overflow. + */ +void sdhci_prepare_adma_table(struct sdhci_adma_desc *table, + struct mmc_data *data, dma_addr_t addr) +{ + uint trans_bytes = data->blocksize * data->blocks; + uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); + struct sdhci_adma_desc *desc = table; + int i = desc_count; + + while (--i) { + sdhci_adma_desc(desc, addr, ADMA_MAX_LEN, false); + addr += ADMA_MAX_LEN; + trans_bytes -= ADMA_MAX_LEN; + desc++; + } + + sdhci_adma_desc(desc, addr, trans_bytes, true); + + flush_cache((dma_addr_t)table, + ROUND(desc_count * sizeof(struct sdhci_adma_desc), + ARCH_DMA_MINALIGN)); +} + +/** + * sdhci_adma_init() - initialize the ADMA descriptor table + * + * @return pointer to the allocated descriptor table or NULL in case of an + * error. + */ +struct sdhci_adma_desc *sdhci_adma_init(void) +{ + return memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); +} diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 7673219fb33..d549a264d73 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -69,57 +69,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data) } } -#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) -static void sdhci_adma_desc(struct sdhci_host *host, dma_addr_t dma_addr, - u16 len, bool end) -{ - struct sdhci_adma_desc *desc; - u8 attr; - - desc = &host->adma_desc_table[host->desc_slot]; - - attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; - if (!end) - host->desc_slot++; - else - attr |= ADMA_DESC_ATTR_END; - - desc->attr = attr; - desc->len = len; - desc->reserved = 0; - desc->addr_lo = lower_32_bits(dma_addr); -#ifdef CONFIG_DMA_ADDR_T_64BIT - desc->addr_hi = upper_32_bits(dma_addr); -#endif -} - -static void sdhci_prepare_adma_table(struct sdhci_host *host, - struct mmc_data *data) -{ - uint trans_bytes = data->blocksize * data->blocks; - uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN); - int i = desc_count; - dma_addr_t dma_addr = host->start_addr; - - host->desc_slot = 0; - - while (--i) { - sdhci_adma_desc(host, dma_addr, ADMA_MAX_LEN, false); - dma_addr += ADMA_MAX_LEN; - trans_bytes -= ADMA_MAX_LEN; - } - - sdhci_adma_desc(host, dma_addr, trans_bytes, true); - - flush_cache((dma_addr_t)host->adma_desc_table, - ROUND(desc_count * sizeof(struct sdhci_adma_desc), - ARCH_DMA_MINALIGN)); -} -#elif defined(CONFIG_MMC_SDHCI_SDMA) -static void sdhci_prepare_adma_table(struct sdhci_host *host, - struct mmc_data *data) -{} -#endif #if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)) static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, int *is_aligned, int trans_bytes) @@ -156,8 +105,11 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, if (host->flags & USE_SDMA) { sdhci_writel(host, phys_to_bus((ulong)host->start_addr), SDHCI_DMA_ADDRESS); - } else if (host->flags & (USE_ADMA | USE_ADMA64)) { - sdhci_prepare_adma_table(host, data); + } +#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA) + else if (host->flags & (USE_ADMA | USE_ADMA64)) { + sdhci_prepare_adma_table(host->adma_desc_table, data, + host->start_addr); sdhci_writel(host, lower_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS); @@ -165,6 +117,7 @@ static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, sdhci_writel(host, upper_32_bits(host->adma_addr), SDHCI_ADMA_ADDRESS_HI); } +#endif } #else static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data, @@ -770,9 +723,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, __func__); return -EINVAL; } - host->adma_desc_table = memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ); - + host->adma_desc_table = sdhci_adma_init(); host->adma_addr = (dma_addr_t)host->adma_desc_table; + #ifdef CONFIG_DMA_ADDR_T_64BIT host->flags |= USE_ADMA64; #else -- cgit v1.2.3 From 46cb3afd3962513345c6a964157fb7b35d014e70 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 29 Sep 2020 21:48:08 +0200 Subject: mmc: do not check argument of free() beforehand free() checks if its argument in NULL. No need to check it twice. Signed-off-by: Heinrich Schuchardt --- drivers/mmc/sh_sdhi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c index 315f95cce82..29f83b65542 100644 --- a/drivers/mmc/sh_sdhi.c +++ b/drivers/mmc/sh_sdhi.c @@ -784,8 +784,7 @@ int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks) return ret; error: - if (host) - free(host); + free(host); return ret; } -- cgit v1.2.3 From c7f4418c8bca79601f62b3b69a4cb24d1adb9d3d Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 30 Sep 2020 15:52:23 +0800 Subject: mmc: fsl_esdhc_imx: replace all readl/writel to esdhc_read32/esdhc_write32 Currently, readl/writel and esdhc_read32/esdhc_write32 are used. To align the usage, change to only use esdhc_read32/esdhc_write32. Signed-off-by: Haibo Chen --- drivers/mmc/fsl_esdhc_imx.c | 64 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index caaef0b7da6..1c015ab7646 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -722,7 +722,7 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) u32 val; if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) { - writel(ESDHC_STROBE_DLL_CTRL_RESET, ®s->strobe_dllctrl); + esdhc_write32(®s->strobe_dllctrl, ESDHC_STROBE_DLL_CTRL_RESET); /* * enable strobe dll ctrl and adjust the delay target @@ -731,10 +731,10 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) val = ESDHC_STROBE_DLL_CTRL_ENABLE | (priv->strobe_dll_delay_target << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); - writel(val, ®s->strobe_dllctrl); + esdhc_write32(®s->strobe_dllctrl, val); /* wait 1us to make sure strobe dll status register stable */ mdelay(1); - val = readl(®s->strobe_dllstat); + val = esdhc_read32(®s->strobe_dllstat); if (!(val & ESDHC_STROBE_DLL_STS_REF_LOCK)) pr_warn("HS400 strobe DLL status REF not lock!\n"); if (!(val & ESDHC_STROBE_DLL_STS_SLV_LOCK)) @@ -748,18 +748,18 @@ static int esdhc_set_timing(struct mmc *mmc) struct fsl_esdhc *regs = priv->esdhc_regs; u32 mixctrl; - mixctrl = readl(®s->mixctrl); + mixctrl = esdhc_read32(®s->mixctrl); mixctrl &= ~(MIX_CTRL_DDREN | MIX_CTRL_HS400_EN); switch (mmc->selected_mode) { case MMC_LEGACY: esdhc_reset_tuning(mmc); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; case MMC_HS_400: case MMC_HS_400_ES: mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN; - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); esdhc_set_strobe_dll(mmc); break; case MMC_HS: @@ -770,12 +770,12 @@ static int esdhc_set_timing(struct mmc *mmc) case UHS_SDR25: case UHS_SDR50: case UHS_SDR104: - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; case UHS_DDR50: case MMC_DDR_52: mixctrl |= MIX_CTRL_DDREN; - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); break; default: printf("Not supported %d\n", mmc->selected_mode); @@ -855,8 +855,8 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) struct fsl_esdhc_priv *priv = dev_get_priv(dev); struct fsl_esdhc *regs = priv->esdhc_regs; struct mmc *mmc = &plat->mmc; - u32 irqstaten = readl(®s->irqstaten); - u32 irqsigen = readl(®s->irqsigen); + u32 irqstaten = esdhc_read32(®s->irqstaten); + u32 irqsigen = esdhc_read32(®s->irqsigen); int i, ret = -ETIMEDOUT; u32 val, mixctrl; @@ -866,25 +866,25 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) /* This is readw/writew SDHCI_HOST_CONTROL2 when tuning */ if (priv->flags & ESDHC_FLAG_STD_TUNING) { - val = readl(®s->autoc12err); - mixctrl = readl(®s->mixctrl); + val = esdhc_read32(®s->autoc12err); + mixctrl = esdhc_read32(®s->mixctrl); val &= ~MIX_CTRL_SMPCLK_SEL; mixctrl &= ~(MIX_CTRL_FBCLK_SEL | MIX_CTRL_AUTO_TUNE_EN); val |= MIX_CTRL_EXE_TUNE; mixctrl |= MIX_CTRL_FBCLK_SEL | MIX_CTRL_AUTO_TUNE_EN; - writel(val, ®s->autoc12err); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->autoc12err, val); + esdhc_write32(®s->mixctrl, mixctrl); } /* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); */ - mixctrl = readl(®s->mixctrl); + mixctrl = esdhc_read32(®s->mixctrl); mixctrl = MIX_CTRL_DTDSEL_READ | (mixctrl & ~MIX_CTRL_SDHCI_MASK); - writel(mixctrl, ®s->mixctrl); + esdhc_write32(®s->mixctrl, mixctrl); - writel(IRQSTATEN_BRR, ®s->irqstaten); - writel(IRQSTATEN_BRR, ®s->irqsigen); + esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); + esdhc_write32(®s->irqsigen, IRQSTATEN_BRR); /* * Issue opcode repeatedly till Execute Tuning is set to 0 or the number @@ -895,22 +895,22 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) if (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200) { if (mmc->bus_width == 8) - writel(0x7080, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7080); else if (mmc->bus_width == 4) - writel(0x7040, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7040); } else { - writel(0x7040, ®s->blkattr); + esdhc_write32(®s->blkattr, 0x7040); } /* sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE) */ - val = readl(®s->mixctrl); + val = esdhc_read32(®s->mixctrl); val = MIX_CTRL_DTDSEL_READ | (val & ~MIX_CTRL_SDHCI_MASK); - writel(val, ®s->mixctrl); + esdhc_write32(®s->mixctrl, val); /* We are using STD tuning, no need to check return value */ mmc_send_tuning(mmc, opcode, NULL); - ctrl = readl(®s->autoc12err); + ctrl = esdhc_read32(®s->autoc12err); if ((!(ctrl & MIX_CTRL_EXE_TUNE)) && (ctrl & MIX_CTRL_SMPCLK_SEL)) { ret = 0; @@ -918,8 +918,8 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) } } - writel(irqstaten, ®s->irqstaten); - writel(irqsigen, ®s->irqsigen); + esdhc_write32(®s->irqstaten, irqstaten); + esdhc_write32(®s->irqsigen, irqsigen); esdhc_stop_tuning(mmc); @@ -1172,7 +1172,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, if (priv->vs18_enable) esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); - writel(SDHCI_IRQ_EN_BITS, ®s->irqstaten); + esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; #ifndef CONFIG_DM_MMC memset(cfg, '\0', sizeof(*cfg)); @@ -1253,10 +1253,10 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; - writel(0, ®s->dllctrl); + esdhc_write32(®s->dllctrl, 0); if (priv->flags & ESDHC_FLAG_USDHC) { if (priv->flags & ESDHC_FLAG_STD_TUNING) { - u32 val = readl(®s->tuning_ctrl); + u32 val = esdhc_read32(®s->tuning_ctrl); val |= ESDHC_STD_TUNING_EN; val &= ~ESDHC_TUNING_START_TAP_MASK; @@ -1275,7 +1275,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, * after the whole tuning procedure always can't get any response. */ val |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; - writel(val, ®s->tuning_ctrl); + esdhc_write32(®s->tuning_ctrl, val); } } @@ -1641,9 +1641,9 @@ static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev) struct fsl_esdhc *regs = priv->esdhc_regs; u32 m; - m = readl(®s->mixctrl); + m = esdhc_read32(®s->mixctrl); m |= MIX_CTRL_HS400_ES; - writel(m, ®s->mixctrl); + esdhc_write32(®s->mixctrl, m); return 0; } -- cgit v1.2.3 From 52faec31827ec1a1837977e29c067424426634c5 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 12 Oct 2020 10:07:13 +0200 Subject: mmc: fsl_esdhc: replace most #ifdefs by IS_ENABLED() Make the code cleaner and drop the old-style #ifdef constructs where it is possible. Signed-off-by: Michael Walle --- drivers/mmc/fsl_esdhc.c | 138 +++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 73 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 10a699f692b..15f8175660f 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -109,17 +109,15 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) if (data) { xfertyp |= XFERTYP_DPSEL; -#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO - if (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK && + if (!IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO) && + cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK && cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200) xfertyp |= XFERTYP_DMAEN; -#endif if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; xfertyp |= XFERTYP_BCEN; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 - xfertyp |= XFERTYP_AC12EN; -#endif + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC111)) + xfertyp |= XFERTYP_AC12EN; } if (data->flags & MMC_DATA_READ) @@ -143,7 +141,6 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) return XFERTYP_CMD(cmd->cmdidx) | xfertyp; } -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO /* * PIO Read/Write Mode reduce the performace as DMA is not used in this mode. */ @@ -206,9 +203,7 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, } } } -#endif -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO static void esdhc_setup_watermark_level(struct fsl_esdhc_priv *priv, struct mmc_data *data) { @@ -228,7 +223,6 @@ static void esdhc_setup_watermark_level(struct fsl_esdhc_priv *priv, wml_value << 16); } } -#endif static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data) { @@ -261,11 +255,10 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, return -EINVAL; } -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO - esdhc_setup_watermark_level(priv, data); -#else - esdhc_setup_dma(priv, data); -#endif + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO)) + esdhc_setup_watermark_level(priv, data); + else + esdhc_setup_dma(priv, data); /* Calculate the timeout period for data transactions */ /* @@ -298,14 +291,13 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc, if (timeout < 0) timeout = 0; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001 - if ((timeout == 4) || (timeout == 8) || (timeout == 12)) + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC_A001) && + (timeout == 4 || timeout == 8 || timeout == 12)) timeout++; -#endif -#ifdef ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE - timeout = 0xE; -#endif + if (IS_ENABLED(ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE)) + timeout = 0xE; + esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); return 0; @@ -325,10 +317,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, struct fsl_esdhc *regs = priv->esdhc_regs; unsigned long start; -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC111) && + cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) return 0; -#endif esdhc_write32(®s->irqstat, -1); @@ -426,37 +417,37 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, /* Wait until all of the blocks are transferred */ if (data) { -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO - esdhc_pio_read_write(priv, data); -#else - flags = DATA_COMPLETE; - if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || - cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) - flags = IRQSTAT_BRR; - - do { - irqstat = esdhc_read32(®s->irqstat); + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_USE_PIO)) { + esdhc_pio_read_write(priv, data); + } else { + flags = DATA_COMPLETE; + if (cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200) + flags = IRQSTAT_BRR; + + do { + irqstat = esdhc_read32(®s->irqstat); - if (irqstat & IRQSTAT_DTOE) { - err = -ETIMEDOUT; - goto out; - } + if (irqstat & IRQSTAT_DTOE) { + err = -ETIMEDOUT; + goto out; + } - if (irqstat & DATA_ERR) { - err = -ECOMM; - goto out; - } - } while ((irqstat & flags) != flags); - - /* - * Need invalidate the dcache here again to avoid any - * cache-fill during the DMA operations such as the - * speculative pre-fetching etc. - */ - dma_unmap_single(priv->dma_addr, - data->blocks * data->blocksize, - mmc_get_dma_dir(data)); -#endif + if (irqstat & DATA_ERR) { + err = -ECOMM; + goto out; + } + } while ((irqstat & flags) != flags); + + /* + * Need invalidate the dcache here again to avoid any + * cache-fill during the DMA operations such as the + * speculative pre-fetching etc. + */ + dma_unmap_single(priv->dma_addr, + data->blocks * data->blocksize, + mmc_get_dma_dir(data)); + } } out: @@ -735,12 +726,10 @@ static void fsl_esdhc_get_cfg_common(struct fsl_esdhc_priv *priv, u32 caps; caps = esdhc_read32(®s->hostcapblt); -#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135 - caps &= ~(HOSTCAPBLT_SRS | HOSTCAPBLT_VS18 | HOSTCAPBLT_VS30); -#endif -#ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33 - caps |= HOSTCAPBLT_VS33; -#endif + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_ESDHC135)) + caps &= ~(HOSTCAPBLT_SRS | HOSTCAPBLT_VS18 | HOSTCAPBLT_VS30); + if (IS_ENABLED(CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33)) + caps |= HOSTCAPBLT_VS33; if (caps & HOSTCAPBLT_VS18) cfg->voltages |= MMC_VDD_165_195; if (caps & HOSTCAPBLT_VS30) @@ -761,19 +750,18 @@ static void fsl_esdhc_get_cfg_common(struct fsl_esdhc_priv *priv, #ifdef CONFIG_OF_LIBFDT __weak int esdhc_status_fixup(void *blob, const char *compat) { -#ifdef CONFIG_FSL_ESDHC_PIN_MUX - if (!hwconfig("esdhc")) { + if (IS_ENABLED(CONFIG_FSL_ESDHC_PIN_MUX) && !hwconfig("esdhc")) { do_fixup_by_compat(blob, compat, "status", "disabled", sizeof("disabled"), 1); return 1; } -#endif + return 0; } -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND -static int fsl_esdhc_get_cd(struct udevice *dev); +#if CONFIG_IS_ENABLED(DM_MMC) +static int fsl_esdhc_get_cd(struct udevice *dev); static void esdhc_disable_for_no_card(void *blob) { struct udevice *dev; @@ -792,6 +780,10 @@ static void esdhc_disable_for_no_card(void *blob) sizeof("disabled"), 1); } } +#else +static void esdhc_disable_for_no_card(void *blob) +{ +} #endif void fdt_fixup_esdhc(void *blob, struct bd_info *bd) @@ -800,9 +792,10 @@ void fdt_fixup_esdhc(void *blob, struct bd_info *bd) if (esdhc_status_fixup(blob, compat)) return; -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND - esdhc_disable_for_no_card(blob); -#endif + + if (IS_ENABLED(CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND)) + esdhc_disable_for_no_card(blob); + do_fixup_by_compat_u32(blob, compat, "clock-frequency", gd->arch.sdhc_clk, 1); } @@ -884,10 +877,9 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) printf("No max bus width provided. Assume 8-bit supported.\n"); } -#ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK - if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK) + if (IS_ENABLED(CONFIG_ESDHC_DETECT_8_BIT_QUIRK)) mmc_cfg->host_caps &= ~MMC_MODE_8BIT; -#endif + mmc_cfg->ops = &esdhc_ops; fsl_esdhc_get_cfg_common(priv, mmc_cfg); @@ -959,10 +951,10 @@ static int fsl_esdhc_probe(struct udevice *dev) if (ret) return ret; -#ifdef CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND - if (!fsl_esdhc_get_cd(dev)) + if (IS_ENABLED(CONFIG_FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND) && + !fsl_esdhc_get_cd(dev)) esdhc_setbits32(&priv->esdhc_regs->proctl, PROCTL_VOLT_SEL); -#endif + return 0; } -- cgit v1.2.3 From 361a422b905052dcbcba61fc1e0d8d804fdca433 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 12 Oct 2020 10:07:14 +0200 Subject: mmc: fsl_esdhc: add ADMA2 support Newer eSDHC controllers support ADMA2 descriptor tables which support 64bit DMA addresses. One notable user of addresses in the upper memory segment is the EFI loader. If support is enabled, but the controller doesn't support ADMA2, we will fall back to SDMA (and thus 32 bit DMA addresses only). Signed-off-by: Michael Walle --- drivers/mmc/Kconfig | 8 ++++++++ drivers/mmc/fsl_esdhc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 88582db58c9..14d79139864 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -755,6 +755,14 @@ config FSL_ESDHC This selects support for the eSDHC (Enhanced Secure Digital Host Controller) found on numerous Freescale/NXP SoCs. +config FSL_ESDHC_SUPPORT_ADMA2 + bool "enable ADMA2 support" + depends on FSL_ESDHC + select MMC_SDHCI_ADMA_HELPERS + help + This enables support for the ADMA2 transfer mode. If supported by the + eSDHC it will allow 64bit DMA addresses. + config FSL_ESDHC_33V_IO_RELIABILITY_WORKAROUND bool "enable eSDHC workaround for 3.3v IO reliability issue" depends on FSL_ESDHC && DM_MMC diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 15f8175660f..642784e1f35 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -27,6 +27,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -52,8 +53,9 @@ struct fsl_esdhc { char reserved1[8]; /* reserved */ uint fevt; /* Force event register */ uint admaes; /* ADMA error status register */ - uint adsaddr; /* ADMA system address register */ - char reserved2[160]; + uint adsaddrl; /* ADMA system address low register */ + uint adsaddrh; /* ADMA system address high register */ + char reserved2[156]; uint hostver; /* Host controller version register */ char reserved3[4]; /* reserved */ uint dmaerraddr; /* DMA error address register */ @@ -99,6 +101,7 @@ struct fsl_esdhc_priv { struct mmc *mmc; #endif struct udevice *dev; + struct sdhci_adma_desc *adma_desc_table; dma_addr_t dma_addr; }; @@ -228,6 +231,7 @@ static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data) { uint trans_bytes = data->blocksize * data->blocks; struct fsl_esdhc *regs = priv->esdhc_regs; + phys_addr_t adma_addr; void *buf; if (data->flags & MMC_DATA_WRITE) @@ -237,9 +241,29 @@ static void esdhc_setup_dma(struct fsl_esdhc_priv *priv, struct mmc_data *data) priv->dma_addr = dma_map_single(buf, trans_bytes, mmc_get_dma_dir(data)); - if (upper_32_bits(priv->dma_addr)) - printf("Cannot use 64 bit addresses with SDMA\n"); - esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); + + if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2) && + priv->adma_desc_table) { + debug("Using ADMA2\n"); + /* prefer ADMA2 if it is available */ + sdhci_prepare_adma_table(priv->adma_desc_table, data, + priv->dma_addr); + + adma_addr = virt_to_phys(priv->adma_desc_table); + esdhc_write32(®s->adsaddrl, lower_32_bits(adma_addr)); + if (IS_ENABLED(CONFIG_DMA_ADDR_T_64BIT)) + esdhc_write32(®s->adsaddrh, upper_32_bits(adma_addr)); + esdhc_clrsetbits32(®s->proctl, PROCTL_DMAS_MASK, + PROCTL_DMAS_ADMA2); + } else { + debug("Using SDMA\n"); + if (upper_32_bits(priv->dma_addr)) + printf("Cannot use 64 bit addresses with SDMA\n"); + esdhc_write32(®s->dsaddr, lower_32_bits(priv->dma_addr)); + esdhc_clrsetbits32(®s->proctl, PROCTL_DMAS_MASK, + PROCTL_DMAS_SDMA); + } + esdhc_write32(®s->blkattr, data->blocks << 16 | data->blocksize); } @@ -911,6 +935,7 @@ static int fsl_esdhc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct fsl_esdhc_plat *plat = dev_get_platdata(dev); struct fsl_esdhc_priv *priv = dev_get_priv(dev); + u32 caps, hostver; fdt_addr_t addr; struct mmc *mmc; int ret; @@ -925,6 +950,21 @@ static int fsl_esdhc_probe(struct udevice *dev) #endif priv->dev = dev; + if (IS_ENABLED(CONFIG_FSL_ESDHC_SUPPORT_ADMA2)) { + /* + * Only newer eSDHC controllers can do ADMA2 if the ADMA flag + * is set in the host capabilities register. + */ + caps = esdhc_read32(&priv->esdhc_regs->hostcapblt); + hostver = esdhc_read32(&priv->esdhc_regs->hostver); + if (caps & HOSTCAPBLT_DMAS && + HOSTVER_VENDOR(hostver) > VENDOR_V_22) { + priv->adma_desc_table = sdhci_adma_init(); + if (!priv->adma_desc_table) + debug("Could not allocate ADMA tables, falling back to SDMA\n"); + } + } + if (gd->arch.sdhc_per_clk) { priv->sdhc_clk = gd->arch.sdhc_per_clk; priv->is_sdhc_per_clk = true; -- cgit v1.2.3