The MMC core uses mmc->clk_disable to request that the card clock is stopped, but the PL180 driver leaves SDI_CLKCR_CLKEN unchanged. This can leave inactive hosts driving their card clocks.
Honor clk_disable when programming the clock control register and enable the controller power-save clock gating. Hardware testing on Ux500 showed that leaving SDI_CLKCR_PWRSAV clear causes external SD card accesses to hang when both the SD and eMMC hosts have been initialized. Linux does not set this bit, but its runtime PM and clock handling differ from U-Boot, where both hosts stay initialized. Acked-by: Peng Fan <[email protected]> Signed-off-by: Linus Walleij <[email protected]> --- drivers/mmc/arm_pl180_mmci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index af21b814641e..528612359789 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -294,6 +294,11 @@ static int host_set_ios(struct mmc *dev) u32 sdi_clkcr; sdi_clkcr = readl(&host->base->clock); + sdi_clkcr |= SDI_CLKCR_PWRSAV; + if (dev->clk_disable) + sdi_clkcr &= ~SDI_CLKCR_CLKEN; + else + sdi_clkcr |= SDI_CLKCR_CLKEN; /* Ramp up the clock rate */ if (dev->clock) { @@ -400,7 +405,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) host->pwr_init = INIT_PWR; host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN | - SDI_CLKCR_HWFC_EN; + SDI_CLKCR_PWRSAV | SDI_CLKCR_HWFC_EN; host->clock_in = clk_get_rate(&clk); cfg->name = dev->name; @@ -418,7 +423,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev) case UX500V2_MMCI_ID: host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | SDI_CLKCR_CLKEN | - SDI_CLKCR_HWFC_EN; + SDI_CLKCR_PWRSAV | SDI_CLKCR_HWFC_EN; cfg->voltages = VOLTAGE_WINDOW_MMC; cfg->f_min = host->clock_in / (2 + SDI_CLKCR_CLKDIV_INIT_V2); host->version2 = true; -- 2.55.0
