ARM: tegra: fix PLLP frequency calc on T210
authorStephen Warren <swarren@nvidia.com>
Wed, 19 Aug 2015 23:03:59 +0000 (17:03 -0600)
committerTom Warren <twarren@nvidia.com>
Wed, 16 Sep 2015 23:10:22 +0000 (16:10 -0700)
AFAIK, for all PLLs on all Tegra SoCs, the primary PLL output frequency
is (input * m) / (n * p). However, PLLP's primary output (pllP_out0) on
T210 is the VCO output, and divp is not applied. pllP_out2 does have divp
applied. All other pllP_outN are divided down from pllP_out0. We only
support pllP_out0 in U-Boot at the time of writing.

Fix clock_get_rate() to handle this special case.

This corrects the returned rate for PLLP to be 408MHz rather than 204MHz.
In turn, this causes high enough dividers to be calculated for the various
peripheral clocks that feed off of PLLP. Without this, some peripherals
failed to operate correctly. For instance, one of my SD cards worked
perfectly but an older (presumably slower) card could not be read.

Note that prior to commit 722e000ccd72 "Tegra: PLL: use per-SoC pllinfo
table instead of PLL_DIVM/N/P, etc.", the calculated PLL frequency was
816MHz since the wrong values were being extracted from the PLLP divider
register. This caused overly large peripheral dividers to be calculated,
which while wrong, didn't cause any correctness issues; things simply ran
slower than they could.

Reported-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/mach-tegra/clock.c

index f9dfcd04115a1267ac39080fddc2feea255ad5b2..b85f63848f2c0cd8cbdc6ef4b28aee5d7113e048 100644 (file)
@@ -483,7 +483,16 @@ unsigned clock_get_rate(enum clock_id clkid)
         * PLLU uses p_mask/p_shift for VCO on all but T210,
         * T210 uses normal DIVP. Handled in pllinfo table.
         */
-       divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
+#ifdef CONFIG_TEGRA210
+       /*
+        * PLLP's primary output (pllP_out0) on T210 is the VCO, and divp is
+        * not applied. pllP_out2 does have divp applied. All other pllP_outN
+        * are divided down from pllP_out0. We only support pllP_out0 in
+        * U-Boot at the time of writing this comment.
+        */
+       if (clkid != CLOCK_ID_PERIPH)
+#endif
+               divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
        do_div(rate, divm);
        return rate;
 }