Skip to content

Commit 00b1d0f

Browse files
shawn1221gregkh
authored andcommitted
mmc: sdhci-of-dwcmshc: Disable clock before DLL configuration
commit 6546a49 upstream. According to the ASIC design recommendations, the clock must be disabled before operating the DLL to prevent glitches that could affect the internal digital logic. In extreme cases, failing to do so may cause the controller to malfunction completely. Adds a step to disable the clock before DLL configuration and re-enables it at the end. Fixes: 08f3dff ("mmc: sdhci-of-dwcmshc: add rockchip platform support") Cc: stable@vger.kernel.org Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0aaa431 commit 00b1d0f

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

drivers/mmc/host/sdhci-of-dwcmshc.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,15 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
243243
extra &= ~BIT(0);
244244
sdhci_writel(host, extra, reg);
245245

246+
/* Disable clock while config DLL */
247+
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
248+
246249
if (clock <= 52000000) {
247250
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
248251
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
249252
dev_err(mmc_dev(host->mmc),
250253
"Can't reduce the clock below 52MHz in HS200/HS400 mode");
251-
return;
254+
goto enable_clk;
252255
}
253256

254257
/*
@@ -268,7 +271,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
268271
DLL_STRBIN_DELAY_NUM_SEL |
269272
DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
270273
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
271-
return;
274+
goto enable_clk;
272275
}
273276

274277
/* Reset DLL */
@@ -295,7 +298,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
295298
500 * USEC_PER_MSEC);
296299
if (err) {
297300
dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
298-
return;
301+
goto enable_clk;
299302
}
300303

301304
extra = 0x1 << 16 | /* tune clock stop en */
@@ -328,6 +331,16 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
328331
DLL_STRBIN_TAPNUM_DEFAULT |
329332
DLL_STRBIN_TAPNUM_FROM_SW;
330333
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
334+
335+
enable_clk:
336+
/*
337+
* The sdclk frequency select bits in SDHCI_CLOCK_CONTROL are not functional
338+
* on Rockchip's SDHCI implementation. Instead, the clock frequency is fully
339+
* controlled via external clk provider by calling clk_set_rate(). Consequently,
340+
* passing 0 to sdhci_enable_clk() only re-enables the already-configured clock,
341+
* which matches the hardware's actual behavior.
342+
*/
343+
sdhci_enable_clk(host, 0);
331344
}
332345

333346
static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)

0 commit comments

Comments
 (0)