[PATCH 2/2] mmc: t210: Fix 'bad' SD-card clock when doing 400KHz card detect

tomcwarren3959 at gmail.com tomcwarren3959 at gmail.com
Thu Mar 26 23:30:22 CET 2020


From: Tom Warren <twarren at nvidia.com>

According to the HW team, for some reason the normal clock select code
picks what appears to be a perfectly valid 375KHz SD card clock, based
on the CAR clock source and SDMMC1 controller register settings (CAR =
408MHz PLLP0 divided by 68 for 6MHz, then a SD Clock Control register
divisor of 16 = 375KHz). But the resulting SD card clock, as measured by
the HW team, is 700KHz, which is out-of-spec. So the WAR is to use the
values given in the TRM PLLP table to generate a 400KHz SD-clock (CAR
clock of 24.7MHz, SD Clock Control divisor of 62) only for SDMMC1 on
T210 when the requested clock is <= 400KHz. Note that as far as I can
tell, the other requests for clocks in the Tegra MMC driver result in
valid SD clocks.

Signed-off-by: Tom Warren <twarren at nvidia.com>
---
Changes for v2:
 - None

 arch/arm/include/asm/arch-tegra/tegra_mmc.h |  2 +-
 drivers/mmc/tegra_mmc.c                     | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/arch-tegra/tegra_mmc.h b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
index a8bfa46..70dcf4a 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_mmc.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
@@ -130,9 +130,9 @@ struct tegra_mmc {
 /* SDMMC1/3 settings from SDMMCx Initialization Sequence of TRM */
 #define MEMCOMP_PADCTRL_VREF	7
 #define AUTO_CAL_ENABLE		(1 << 29)
-#if defined(CONFIG_TEGRA210)
 #define AUTO_CAL_ACTIVE		(1 << 31)
 #define AUTO_CAL_START		(1 << 31)
+#if defined(CONFIG_TEGRA210)
 #define AUTO_CAL_PD_OFFSET	(0x7D << 8)
 #define AUTO_CAL_PU_OFFSET	(0 << 0)
 #define IO_TRIM_BYPASS_MASK	(1 << 2)
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index 73ac58c..03110ba 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -376,6 +376,24 @@ static void tegra_mmc_change_clock(struct tegra_mmc_priv *priv, uint clock)
 
 	rate = clk_set_rate(&priv->clk, clock);
 	div = (rate + clock - 1) / clock;
+
+#if defined(CONFIG_TEGRA210)
+	if (priv->mmc_id == PERIPH_ID_SDMMC1 && clock <= 400000) {
+		/* clock_adjust_periph_pll_div() chooses a 'bad' clock
+		 * on SDMMC1 T210, so skip it here and force a clock
+		 * that's been spec'd in the table in the TRM for
+		 * card-detect (400KHz).
+		 */
+		uint effective_rate = clock_adjust_periph_pll_div(priv->mmc_id,
+				CLOCK_ID_PERIPH, 24727273, NULL);
+		div = 62;
+
+		debug("%s: WAR: Using SDMMC1 clock of %u, div %d to achieve %dHz card clock ...\n",
+			__func__, effective_rate, div, clock);
+	} else
+		clock_adjust_periph_pll_div(priv->mmc_id, CLOCK_ID_PERIPH, clock,
+				    &div);
+#endif
 	debug("div = %d\n", div);
 
 	writew(0, &priv->reg->clkcon);
-- 
1.8.2.1.610.g562af5b


-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------


More information about the U-Boot mailing list