Skip to content

Commit 6546a49

Browse files
shawn1221Ulf Hansson
authored andcommitted
mmc: sdhci-of-dwcmshc: Disable clock before DLL configuration
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>
1 parent 873cc55 commit 6546a49

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
@@ -783,12 +783,15 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
783783
extra |= BIT(4);
784784
sdhci_writel(host, extra, reg);
785785

786+
/* Disable clock while config DLL */
787+
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
788+
786789
if (clock <= 52000000) {
787790
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
788791
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
789792
dev_err(mmc_dev(host->mmc),
790793
"Can't reduce the clock below 52MHz in HS200/HS400 mode");
791-
return;
794+
goto enable_clk;
792795
}
793796

794797
/*
@@ -808,7 +811,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
808811
DLL_STRBIN_DELAY_NUM_SEL |
809812
DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
810813
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
811-
return;
814+
goto enable_clk;
812815
}
813816

814817
/* Reset DLL */
@@ -835,7 +838,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
835838
500 * USEC_PER_MSEC);
836839
if (err) {
837840
dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
838-
return;
841+
goto enable_clk;
839842
}
840843

841844
extra = 0x1 << 16 | /* tune clock stop en */
@@ -868,6 +871,16 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
868871
DLL_STRBIN_TAPNUM_DEFAULT |
869872
DLL_STRBIN_TAPNUM_FROM_SW;
870873
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
874+
875+
enable_clk:
876+
/*
877+
* The sdclk frequency select bits in SDHCI_CLOCK_CONTROL are not functional
878+
* on Rockchip's SDHCI implementation. Instead, the clock frequency is fully
879+
* controlled via external clk provider by calling clk_set_rate(). Consequently,
880+
* passing 0 to sdhci_enable_clk() only re-enables the already-configured clock,
881+
* which matches the hardware's actual behavior.
882+
*/
883+
sdhci_enable_clk(host, 0);
871884
}
872885

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

0 commit comments

Comments
 (0)