Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci-msm: Avoid early clock doubling during HS400 transition

According to the hardware programming guide, the clock frequency must
remain below 52MHz during the transition to HS400 mode.

However,in the current implementation, the timing is set to HS400 (a
DDR mode) before adjusting the clock. This causes the clock to double
prematurely to 104MHz during the transition phase, violating the
specification and potentially resulting in CRC errors or CMD timeouts.

This change ensures that clock doubling is avoided during intermediate
transitions and is applied only when the card requires a 200MHz clock
for HS400 operation.

Signed-off-by: Sarthak Garg <sarthak.garg@oss.qualcomm.com>
Reviewed-by: Bjorn Andersson <andersson@kernel.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Sarthak Garg and committed by
Ulf Hansson
b1f856b1 8a4a16f8

+15 -12
+15 -12
drivers/mmc/host/sdhci-msm.c
··· 344 344 writel_relaxed(val, host->ioaddr + offset); 345 345 } 346 346 347 - static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host) 347 + static unsigned int msm_get_clock_mult_for_bus_mode(struct sdhci_host *host, 348 + unsigned int clock, 349 + unsigned int timing) 348 350 { 349 - struct mmc_ios ios = host->mmc->ios; 350 351 /* 351 352 * The SDHC requires internal clock frequency to be double the 352 353 * actual clock that will be set for DDR mode. The controller 353 354 * uses the faster clock(100/400MHz) for some of its parts and 354 355 * send the actual required clock (50/200MHz) to the card. 355 356 */ 356 - if (ios.timing == MMC_TIMING_UHS_DDR50 || 357 - ios.timing == MMC_TIMING_MMC_DDR52 || 358 - ios.timing == MMC_TIMING_MMC_HS400 || 357 + if (timing == MMC_TIMING_UHS_DDR50 || 358 + timing == MMC_TIMING_MMC_DDR52 || 359 + (timing == MMC_TIMING_MMC_HS400 && 360 + clock == MMC_HS200_MAX_DTR) || 359 361 host->flags & SDHCI_HS400_TUNING) 360 362 return 2; 361 363 return 1; 362 364 } 363 365 364 366 static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, 365 - unsigned int clock) 367 + unsigned int clock, 368 + unsigned int timing) 366 369 { 367 370 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 368 371 struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 369 - struct mmc_ios curr_ios = host->mmc->ios; 370 372 struct clk *core_clk = msm_host->bulk_clks[0].clk; 371 373 unsigned long achieved_rate; 372 374 unsigned int desired_rate; 373 375 unsigned int mult; 374 376 int rc; 375 377 376 - mult = msm_get_clock_mult_for_bus_mode(host); 378 + mult = msm_get_clock_mult_for_bus_mode(host, clock, timing); 377 379 desired_rate = clock * mult; 378 380 rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), desired_rate); 379 381 if (rc) { 380 382 pr_err("%s: Failed to set clock at rate %u at timing %d\n", 381 - mmc_hostname(host->mmc), desired_rate, curr_ios.timing); 383 + mmc_hostname(host->mmc), desired_rate, timing); 382 384 return; 383 385 } 384 386 ··· 399 397 msm_host->clk_rate = desired_rate; 400 398 401 399 pr_debug("%s: Setting clock at rate %lu at timing %d\n", 402 - mmc_hostname(host->mmc), achieved_rate, curr_ios.timing); 400 + mmc_hostname(host->mmc), achieved_rate, timing); 403 401 } 404 402 405 403 /* Platform specific tuning */ ··· 1241 1239 */ 1242 1240 if (host->flags & SDHCI_HS400_TUNING) { 1243 1241 sdhci_msm_hc_select_mode(host); 1244 - msm_set_clock_rate_for_bus_mode(host, ios.clock); 1242 + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); 1245 1243 host->flags &= ~SDHCI_HS400_TUNING; 1246 1244 } 1247 1245 ··· 1866 1864 { 1867 1865 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1868 1866 struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 1867 + struct mmc_ios ios = host->mmc->ios; 1869 1868 1870 1869 if (!clock) { 1871 1870 host->mmc->actual_clock = msm_host->clk_rate = 0; ··· 1875 1872 1876 1873 sdhci_msm_hc_select_mode(host); 1877 1874 1878 - msm_set_clock_rate_for_bus_mode(host, clock); 1875 + msm_set_clock_rate_for_bus_mode(host, ios.clock, ios.timing); 1879 1876 out: 1880 1877 __sdhci_msm_set_clock(host, clock); 1881 1878 }