ARM: tegra: Implement clk_m
authorThierry Reding <treding@nvidia.com>
Thu, 20 Aug 2015 09:42:19 +0000 (11:42 +0200)
committerTom Warren <twarren@nvidia.com>
Wed, 16 Sep 2015 23:10:22 +0000 (16:10 -0700)
On currently supported SoCs, clk_m always runs at the same frequency as
the oscillator input. However newer SoC generations such as Tegra210 no
longer have that restriction. Prepare for that by separating clk_m from
the oscillator clock and allow SoC code to override the clk_m rate.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/include/asm/arch-tegra/clock.h
arch/arm/include/asm/arch-tegra114/clock-tables.h
arch/arm/include/asm/arch-tegra124/clock-tables.h
arch/arm/include/asm/arch-tegra20/clock-tables.h
arch/arm/include/asm/arch-tegra210/clock-tables.h
arch/arm/include/asm/arch-tegra30/clock-tables.h
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/tegra210/clock.c

index d570d7f134a8d32e9fb63be42ee920ea13d1cd88..e56031d1afa7e8bd5508447be3e2c16aa0d9417b 100644 (file)
@@ -44,6 +44,9 @@ enum {
 /* return the current oscillator clock frequency */
 enum clock_osc_freq clock_get_osc_freq(void);
 
+/* return the clk_m frequency */
+unsigned int clk_m_get_rate(unsigned int parent_rate);
+
 /**
  * Start PLL using the provided configuration parameters.
  *
@@ -338,8 +341,8 @@ void arch_timer_init(void);
 
 void tegra30_set_up_pllp(void);
 
-/* Number of PLL-based clocks (i.e. not OSC or 32KHz) */
-#define CLOCK_ID_PLL_COUNT     (CLOCK_ID_COUNT - 2)
+/* Number of PLL-based clocks (i.e. not OSC, MCLK or 32KHz) */
+#define CLOCK_ID_PLL_COUNT     (CLOCK_ID_COUNT - 3)
 
 struct clk_pll_info {
        u32     m_shift:5;      /* DIVM_SHIFT */
index d8fa0e1d2ceee25da726165f4361cc5e08673143..3f910f5ae8b94d7191d0a369e93d4ebca7db8b49 100644 (file)
@@ -38,6 +38,7 @@ enum clock_id {
        /* These are the base clocks (inputs to the Tegra SOC) */
        CLOCK_ID_32KHZ,
        CLOCK_ID_OSC,
+       CLOCK_ID_CLK_M,
 
        CLOCK_ID_COUNT, /* number of PLLs */
        CLOCK_ID_DISPLAY2,      /* placeholder */
index 3c67e72afe89ddb82ec8ebb78e150f1141a98b0e..9466b4ffb33eba7c1b2e47f7bd6986f36547a3b6 100644 (file)
@@ -30,6 +30,7 @@ enum clock_id {
        /* These are the base clocks (inputs to the Tegra SoC) */
        CLOCK_ID_32KHZ,
        CLOCK_ID_OSC,
+       CLOCK_ID_CLK_M,
 
        CLOCK_ID_COUNT, /* number of PLLs */
 
index 894be088cde2dcfae35d7593d864491cfd90b86f..812e8760d0cd1f60bce35cc3d31ee4d010cc69fc 100644 (file)
@@ -29,6 +29,7 @@ enum clock_id {
        /* These are the base clocks (inputs to the Tegra SOC) */
        CLOCK_ID_32KHZ,
        CLOCK_ID_OSC,
+       CLOCK_ID_CLK_M,
 
        CLOCK_ID_COUNT, /* number of clocks */
        CLOCK_ID_NONE = -1,
index 175040dae618a4e9f02e1a775704e6681609b262..a612485d8e235bfe3064b12b5f1b459244b0dee1 100644 (file)
@@ -30,6 +30,7 @@ enum clock_id {
        /* These are the base clocks (inputs to the Tegra SoC) */
        CLOCK_ID_32KHZ,
        CLOCK_ID_OSC,
+       CLOCK_ID_CLK_M,
 
        CLOCK_ID_COUNT, /* number of PLLs */
 
index cb619f1f2d61551a8b5b24d0a0949ea1eb60d2a6..f7c7af80faafe1f4b8a193639bb79025f4afe524 100644 (file)
@@ -38,6 +38,7 @@ enum clock_id {
        /* These are the base clocks (inputs to the Tegra SOC) */
        CLOCK_ID_32KHZ,
        CLOCK_ID_OSC,
+       CLOCK_ID_CLK_M,
 
        CLOCK_ID_COUNT, /* number of PLLs */
        CLOCK_ID_DISPLAY2,      /* Tegra3, placeholder */
index b85f63848f2c0cd8cbdc6ef4b28aee5d7113e048..f75c6c664a25a0071c68197f3fcf527b889c3582 100644 (file)
@@ -461,6 +461,11 @@ void reset_cmplx_set_enable(int cpu, int which, int reset)
                writel(mask, &clkrst->crc_cpu_cmplx_clr);
 }
 
+unsigned int __weak clk_m_get_rate(unsigned int parent_rate)
+{
+       return parent_rate;
+}
+
 unsigned clock_get_rate(enum clock_id clkid)
 {
        struct clk_pll *pll;
@@ -472,6 +477,9 @@ unsigned clock_get_rate(enum clock_id clkid)
        if (clkid == CLOCK_ID_OSC)
                return parent_rate;
 
+       if (clkid == CLOCK_ID_CLK_M)
+               return clk_m_get_rate(parent_rate);
+
        pll = get_pll(clkid);
        if (!pll)
                return 0;
@@ -622,8 +630,10 @@ void clock_init(void)
        pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU);
        pll_rate[CLOCK_ID_SFROM32KHZ] = 32768;
        pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC);
+       pll_rate[CLOCK_ID_CLK_M] = clock_get_rate(CLOCK_ID_CLK_M);
 
        debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]);
+       debug("CLKM = %d\n", pll_rate[CLOCK_ID_CLK_M]);
        debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]);
        debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]);
        debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]);
index 830a33ffc9385196da9d1f451219ef291e824640..146bb6453a19c5b4a135aa8fab4b1b4582356e56 100644 (file)
@@ -998,6 +998,17 @@ void clock_early_init(void)
        udelay(2);
 }
 
+unsigned int clk_m_get_rate(unsigned parent_rate)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 value, div;
+
+       value = readl(&clkrst->crc_spare_reg0);
+       div = ((value >> 2) & 0x3) + 1;
+
+       return parent_rate / div;
+}
+
 void arch_timer_init(void)
 {
        struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;