ARM: tegra: don't exceed AVP limits when configuring PLLP
authorJimmy Zhang <jimmzhang@nvidia.com>
Fri, 24 Jan 2014 17:37:36 +0000 (10:37 -0700)
committerTom Warren <twarren@nvidia.com>
Mon, 3 Feb 2014 16:46:45 +0000 (09:46 -0700)
Based on the Tegra TRM, the system clock (which is the AVP clock) can
run up to 275MHz. On power on, the default sytem clock source is set to
PLLP_OUT0. In function clock_early_init(), PLLP_OUT0 will be set to
408MHz which is beyond system clock's upper limit.

The fix is to set the system clock to CLK_M before initializing PLLP,
and then switch back to PLLP_OUT4, which has an appropriate divider
configured, after PLLP has been configured

Implement this logic in new function tegra30_set_up_pllp(),
which sets up PLLP and all PLLP_OUT* dividers, and handles the AVP
clock switching. Remove the duplicate PLLP setup from pllx_set_rate()
and adjust_pllp_out_freqs().

Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com>
[swarren, significantly refactored the change]
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Thierry Reding <treding@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/cpu/arm720t/tegra-common/cpu.c
arch/arm/cpu/arm720t/tegra114/cpu.c
arch/arm/cpu/arm720t/tegra30/cpu.c
arch/arm/cpu/tegra-common/clock.c
arch/arm/cpu/tegra114-common/clock.c
arch/arm/cpu/tegra30-common/clock.c
arch/arm/include/asm/arch-tegra/clk_rst.h
arch/arm/include/asm/arch-tegra/clock.h

index 72c69b914c7fe188ff86d3e26ba7ce98ade2ec49..03f67b163cc5fe806b4d59095a65ff8e0dbb9c89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -114,24 +114,6 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
        },
 };
 
-void adjust_pllp_out_freqs(void)
-{
-       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
-       struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH];
-       u32 reg;
-
-       /* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
-       reg = readl(&pll->pll_out[0]);  /* OUTA, contains OUT2 / OUT1 */
-       reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR
-               | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR;
-       writel(reg, &pll->pll_out[0]);
-
-       reg = readl(&pll->pll_out[1]);   /* OUTB, contains OUT4 / OUT3 */
-       reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR
-               | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR;
-       writel(reg, &pll->pll_out[1]);
-}
-
 int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
                u32 divp, u32 cpcon)
 {
@@ -207,12 +189,6 @@ void init_pllx(void)
        /* set pllx */
        sel = &tegra_pll_x_table[chip_sku][osc];
        pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
-
-       /* adjust PLLP_out1-4 on T3x/T114 */
-       if (soc_type >= CHIPID_TEGRA30) {
-               debug("  init_pllx: adjusting PLLP out freqs\n");
-               adjust_pllp_out_freqs();
-       }
 }
 
 void enable_cpu_clock(int enable)
index 7a1747a3beb838b0909e1ec827a692c529136a0e..385e1a1c86e0610f4509dc32867b8f66e81abfe2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -126,18 +126,6 @@ void t114_init_clocks(void)
        /* Set active CPU cluster to G */
        clrbits_le32(&flow->cluster_control, 1);
 
-       /*
-        * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
-        * at 108 MHz. This is glitch free as only the source is changed, no
-        * special precaution needed.
-        */
-       val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
-               (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
-       writel(val, &clkrst->crc_sclk_brst_pol);
-
        writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
 
        debug("Setting up PLLX\n");
index e16235748449c61bd54715643dd7ee9d278485c5..a80648389c7cc14d1bf064aa93b04ea703a0d87e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -84,18 +84,6 @@ void t30_init_clocks(void)
        /* Set active CPU cluster to G */
        clrbits_le32(flow->cluster_control, 1 << 0);
 
-       /*
-        * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
-        * at 108 MHz. This is glitch free as only the source is changed, no
-        * special precaution needed.
-        */
-       val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
-               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
-               (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
-       writel(val, &clkrst->crc_sclk_brst_pol);
-
        writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
 
        val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
index 33bb19084b8cdb9a3ab2296d2bd9c71a8edc425e..11c7435505c1d17d53ccf10c4040f640d5a4afde 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -575,3 +575,95 @@ void clock_init(void)
        /* Do any special system timer/TSC setup */
        arch_timer_init();
 }
+
+static void set_avp_clock_source(u32 src)
+{
+       struct clk_rst_ctlr *clkrst =
+                       (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 val;
+
+       val = (src << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+               (src << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+               (src << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+               (src << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+               (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+       writel(val, &clkrst->crc_sclk_brst_pol);
+       udelay(3);
+}
+
+/*
+ * This function is useful on Tegra30, and any later SoCs that have compatible
+ * PLLP configuration registers.
+ */
+void tegra30_set_up_pllp(void)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 reg;
+
+       /*
+        * Based on the Tegra TRM, the system clock (which is the AVP clock) can
+        * run up to 275MHz. On power on, the default sytem clock source is set
+        * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to
+        * 408MHz which is beyond system clock's upper limit.
+        *
+        * The fix is to set the system clock to CLK_M before initializing PLLP,
+        * and then switch back to PLLP_OUT4, which has an appropriate divider
+        * configured, after PLLP has been configured
+        */
+       set_avp_clock_source(SCLK_SOURCE_CLKM);
+
+       /*
+        * PLLP output frequency set to 408Mhz
+        * PLLC output frequency set to 228Mhz
+        */
+       switch (clock_get_osc_freq()) {
+       case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+               clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
+               clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
+               break;
+
+       case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+               clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
+               clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
+               break;
+
+       case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+               clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
+               clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+               break;
+       case CLOCK_OSC_FREQ_19_2:
+       default:
+               /*
+                * These are not supported. It is too early to print a
+                * message and the UART likely won't work anyway due to the
+                * oscillator being wrong.
+                */
+               break;
+       }
+
+       /* Set PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
+
+       /* OUT1, 2 */
+       /* Assert RSTN before enable */
+       reg = PLLP_OUT2_RSTN_EN | PLLP_OUT1_RSTN_EN;
+       writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
+       /* Set divisor and reenable */
+       reg = (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO)
+               | PLLP_OUT2_OVR | PLLP_OUT2_CLKEN | PLLP_OUT2_RSTN_DIS
+               | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO)
+               | PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS;
+       writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
+
+       /* OUT3, 4 */
+       /* Assert RSTN before enable */
+       reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN;
+       writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+       /* Set divisor and reenable */
+       reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO)
+               | PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS
+               | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO)
+               | PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS;
+       writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+
+       set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4);
+}
index 3bede71a7a1f7efaf3077c105bbe2e3627c741d1..d5194e11b5fd88e8269b64b6de704922cdddf2e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -604,26 +604,24 @@ void clock_early_init(void)
        struct clk_rst_ctlr *clkrst =
                (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
 
+       tegra30_set_up_pllp();
+
        /*
-        * PLLP output frequency set to 408Mhz
         * PLLC output frequency set to 600Mhz
         * PLLD output frequency set to 925Mhz
         */
        switch (clock_get_osc_freq()) {
        case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
                clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
                clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
                break;
 
        case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
                clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
                clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
                break;
 
        case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
                clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
                clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
                break;
index 33528702185e8e5f990fa41ceeb8af91388a1a36..80ba2d8c1ca5fa5f315acb3ed593a7aa73b808bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -581,34 +581,7 @@ enum periph_id clk_id_to_periph_id(int clk_id)
 
 void clock_early_init(void)
 {
-       /*
-        * PLLP output frequency set to 408Mhz
-        * PLLC output frequency set to 228Mhz
-        */
-       switch (clock_get_osc_freq()) {
-       case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
-               clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
-               break;
-
-       case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
-               clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
-               break;
-
-       case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
-               clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
-               clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
-               break;
-       case CLOCK_OSC_FREQ_19_2:
-       default:
-               /*
-                * These are not supported. It is too early to print a
-                * message and the UART likely won't work anyway due to the
-                * oscillator being wrong.
-                */
-               break;
-       }
+       tegra30_set_up_pllp();
 }
 
 void arch_timer_init(void)
index f07b83d26af41ea92bc618af3ccb8460d5499682..021cfcc3c602334f772fc6ad2315032e265401f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  (C) Copyright 2010,2011
+ *  (C) Copyright 2010-2014
  *  NVIDIA Corporation <www.nvidia.com>
  *
  * SPDX-License-Identifier:    GPL-2.0+
@@ -209,6 +209,20 @@ enum {
        IN_408_OUT_9_6_DIVISOR = 83,
 };
 
+#define PLLP_OUT1_RSTN_DIS     (1 << 0)
+#define PLLP_OUT1_RSTN_EN      (0 << 0)
+#define PLLP_OUT1_CLKEN                (1 << 1)
+#define PLLP_OUT2_RSTN_DIS     (1 << 16)
+#define PLLP_OUT2_RSTN_EN      (0 << 16)
+#define PLLP_OUT2_CLKEN                (1 << 17)
+
+#define PLLP_OUT3_RSTN_DIS     (1 << 0)
+#define PLLP_OUT3_RSTN_EN      (0 << 0)
+#define PLLP_OUT3_CLKEN                (1 << 1)
+#define PLLP_OUT4_RSTN_DIS     (1 << 16)
+#define PLLP_OUT4_RSTN_EN      (0 << 16)
+#define PLLP_OUT4_CLKEN                (1 << 17)
+
 /* CLK_RST_CONTROLLER_UTMIP_PLL_CFG1_0 */
 #define PLLU_POWERDOWN         (1 << 16)
 #define PLL_ENABLE_POWERDOWN   (1 << 14)
index 2f85696a58549c6feb81b330548618fd1c30da17..9d8114c4ecfaf87e4c6bf5c6910fffe92ce35af0 100644 (file)
@@ -320,4 +320,6 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon);
 /* SoC-specific TSC init */
 void arch_timer_init(void);
 
+void tegra30_set_up_pllp(void);
+
 #endif  /* _TEGRA_CLOCK_H_ */