diff mbox series

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

Message ID 1584395953-11561-3-git-send-email-twarren@nvidia.com
State Accepted
Commit a482f32992230d8bdae2caa72056ab7d9208d5f0
Headers show
Series mmc: t210: fix autocal and 400KHz clock | expand

Commit Message

Tom Warren March 16, 2020, 9:59 p.m. UTC
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>
---
 arch/arm/include/asm/arch-tegra/tegra_mmc.h |  2 +-
 drivers/mmc/tegra_mmc.c                     | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)
diff mbox series

Patch

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 a4bd679..3ca947c 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);