[PATCH 1/5] mmc: fsl_esdhc_imx: Enable AHB/IPG clk

From: Peng Fan peng.fan@nxp.com
Only enable PER clk is not enough, also need to enable AHB/IPG clk.
Reviewed-by: Ye Li ye.li@nxp.com Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/mmc/fsl_esdhc_imx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 03de7dcd505..f22b03657a3 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -148,6 +148,8 @@ struct fsl_esdhc_priv { struct fsl_esdhc *esdhc_regs; unsigned int sdhc_clk; struct clk per_clk; + struct clk ipg_clk; + struct clk ahb_clk; unsigned int clock; unsigned int mode; #if !CONFIG_IS_ENABLED(DM_MMC) @@ -1521,6 +1523,24 @@ static int fsl_esdhc_probe(struct udevice *dev)
#if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */ + ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk); + if (!ret) { + ret = clk_enable(&priv->ipg_clk); + if (ret) { + printf("Failed to enable ipg_clk\n"); + return ret; + } + } + + ret = clk_get_by_name(dev, "ahb", &priv->ahb_clk); + if (!ret) { + ret = clk_enable(&priv->ahb_clk); + if (ret) { + printf("Failed to enable ahb_clk\n"); + return ret; + } + } + ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { printf("Failed to get per_clk\n");

From: Ye Li ye.li@nxp.com
According to SD and MMC spec, 74 clocks must be sent to device after power stable. This is need in reinit ops for DM MMC or init ops for non-DM MMC after power cycle.
So set the INTIA to send 80 clocks in esdhc_init_common and move its calling from probe to reinit.
However, on 8MQ EVK and 8QXP MEK with some brands of SD cards, sending 80 clocks may not work well.
The root cause is related with power up time. According to spec, after power stable, host shall supply at least 74 SD clocks to the SD card with the maximum of 1ms. However, the power ram up time is related with the characteristic of SD card. At the moment of sending 74 SD clocks, the power probably not ram up to the operating level on the problematic cards. Then cause the cards not ready.
This patch changes to send SD clock with 1ms duration to replace 80 SD clocks (0.2ms at 400Khz clock). This way meets the spec requirement as well, and adds the margin for power ram up time to be compatible with the problematic SD cards. This is also aligned with implementation which has FORCE clock always on.
Reviewed-and-tested-by: Haibo Chen haibo.chen@nxp.com Signed-off-by: Ye Li ye.li@nxp.com Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/mmc/fsl_esdhc_imx.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index f22b03657a3..7215237c458 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1036,6 +1036,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
+ /* max 1ms delay with clock on for initialization */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + udelay(1000); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + return 0; }
@@ -1581,7 +1586,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
upriv->mmc = mmc;
- return esdhc_init_common(priv, mmc); + return 0; }
static int fsl_esdhc_get_cd(struct udevice *dev) @@ -1633,6 +1638,14 @@ static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, return esdhc_wait_dat0_common(priv, state, timeout_us); }
+static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_plat(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, @@ -1644,6 +1657,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, #endif .wait_dat0 = fsl_esdhc_wait_dat0, + .reinit = fsl_esdhc_reinit, };
static struct esdhc_soc_data usdhc_imx7d_data = {

From: Ye Li ye.li@nxp.com
The plat->cfg is wrongly memset to 0, so the host_caps value configured in fsl_esdhc_initialize is reset. Remove the unnecessary memset since plat is allocated via calloc.
Reviewed-by: Peng Fan peng.fan@nxp.com Signed-off-by: Ye Li ye.li@nxp.com Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/mmc/fsl_esdhc_imx.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 7215237c458..e371b32d2a3 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1195,8 +1195,6 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv,
esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; - if (!CONFIG_IS_ENABLED(DM_MMC)) - memset(cfg, '\0', sizeof(*cfg));
caps = esdhc_read32(®s->hostcapblt);

From: Ye Li ye.li@nxp.com
The memory of priv and plat are leaked if max_bus_width is wrong.
Signed-off-by: Ye Li ye.li@nxp.com Reviewed-by: Peng Fan peng.fan@nxp.com Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/mmc/fsl_esdhc_imx.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index e371b32d2a3..2413bafc32f 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1328,6 +1328,8 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) break; default: printf("invalid max bus width %u\n", cfg->max_bus_width); + free(plat); + free(priv); return -EINVAL; }

From: Peng Fan peng.fan@nxp.com
When supporting partition reset for SoC such as i.MX95 , the Linux Kernel may have configured the tuning, while after force reset by wdog or else, uboot CMD0 will never pass unless config RSTT to reset tuning logic.
Since RSTA and RSTT are independent, so need both to be reseted in the controller.
Acked-by: Haibo Chen haibo.chen@nxp.com Signed-off-by: Peng Fan peng.fan@nxp.com --- drivers/mmc/fsl_esdhc_imx.c | 8 ++++---- include/fsl_esdhc_imx.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 2413bafc32f..d23de876c6a 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -988,11 +988,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) ulong start;
/* Reset the entire host controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT);
/* Wait until the controller is available */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 1000) return -ETIMEDOUT; } @@ -1096,11 +1096,11 @@ static int esdhc_reset(struct fsl_esdhc *regs) ulong start;
/* reset the controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT);
/* hardware clears the bit when it is done */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 100) { printf("MMC/SD: Reset never completed.\n"); return -ETIMEDOUT; diff --git a/include/fsl_esdhc_imx.h b/include/fsl_esdhc_imx.h index b8efd2a1664..8612b56609e 100644 --- a/include/fsl_esdhc_imx.h +++ b/include/fsl_esdhc_imx.h @@ -31,6 +31,7 @@ #define SYSCTL_RSTA 0x01000000 #define SYSCTL_RSTC 0x02000000 #define SYSCTL_RSTD 0x04000000 +#define SYSCTL_RSTT 0x10000000
#define VENDORSPEC_CKEN 0x00004000 #define VENDORSPEC_PEREN 0x00002000

Hi Peng,
On Mon, Sep 30, 2024 at 2:47 AM Peng Fan (OSS) peng.fan@oss.nxp.com wrote:
From: Peng Fan peng.fan@nxp.com
Only enable PER clk is not enough, also need to enable AHB/IPG clk.
Currently, the driver is working and now extra clocks need to be turned on.
Please provide more details here as to why this is a problem now and it wasn't before.
#if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */
ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk);
if (!ret) {
ret = clk_enable(&priv->ipg_clk);
if (ret) {
printf("Failed to enable ipg_clk\n");
return ret;
}
}
ret = clk_get_by_name(dev, "ahb", &priv->ahb_clk);
if (!ret) {
ret = clk_enable(&priv->ahb_clk);
if (ret) {
printf("Failed to enable ahb_clk\n");
return ret;
In the case of failure, the previously enabled clock must be disabled.
Would it be better to use clk_enable_bulk() here instead?

Subject: Re: [PATCH 1/5] mmc: fsl_esdhc_imx: Enable AHB/IPG clk
Hi Peng,
On Mon, Sep 30, 2024 at 2:47 AM Peng Fan (OSS) peng.fan@oss.nxp.com wrote:
From: Peng Fan peng.fan@nxp.com
Only enable PER clk is not enough, also need to enable AHB/IPG clk.
Currently, the driver is working and now extra clocks need to be turned on.
Please provide more details here as to why this is a problem now and it wasn't before.
With partition reset supported, when SPL rerun after partition reset, the mmc clk may already be disabled in linux mmc runtime suspend. So need to enable all the clks for mmc in SPL/U-boot.
#if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */
ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk);
if (!ret) {
ret = clk_enable(&priv->ipg_clk);
if (ret) {
printf("Failed to enable ipg_clk\n");
return ret;
}
}
ret = clk_get_by_name(dev, "ahb", &priv->ahb_clk);
if (!ret) {
ret = clk_enable(&priv->ahb_clk);
if (ret) {
printf("Failed to enable ahb_clk\n");
return ret;
In the case of failure, the previously enabled clock must be disabled.
Would it be better to use clk_enable_bulk() here instead?
I will give a look at this.
Thanks, Peng.
participants (3)
-
Fabio Estevam
-
Peng Fan
-
Peng Fan (OSS)