]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
clk: tegra: clk-super: Fix to enable PLLP branches to CPU
authorSowjanya Komatineni <skomatineni@nvidia.com>
Fri, 16 Aug 2019 19:41:54 +0000 (12:41 -0700)
committerThierry Reding <treding@nvidia.com>
Mon, 11 Nov 2019 13:53:03 +0000 (14:53 +0100)
This patch has a fix to enable PLLP branches to CPU before changing
the CPU cluster clock source to PLLP for Gen5 Super clock and
disables PLLP branches to CPU when not in use.

During system suspend entry and exit, CPU source will be switched
to PLLP and this needs PLLP branches to be enabled to CPU prior to
the switch.

On system resume, warmboot code enables PLLP branches to CPU and
powers up the CPU with PLLP clock source.

Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/clk/tegra/clk-super.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk.c
drivers/clk/tegra/clk.h

index 39ef31b46df5946d3e063c6e48f782accdf598ff..e2a1e95a8db787a729e596d165ba0dc740b59572 100644 (file)
@@ -28,6 +28,9 @@
 #define super_state_to_src_shift(m, s) ((m->width * s))
 #define super_state_to_src_mask(m) (((1 << m->width) - 1))
 
+#define CCLK_SRC_PLLP_OUT0 4
+#define CCLK_SRC_PLLP_OUT4 5
+
 static u8 clk_super_get_parent(struct clk_hw *hw)
 {
        struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
@@ -97,12 +100,23 @@ static int clk_super_set_parent(struct clk_hw *hw, u8 index)
                if (index == mux->div2_index)
                        index = mux->pllx_index;
        }
+
+       /* enable PLLP branches to CPU before selecting PLLP source */
+       if ((mux->flags & TEGRA210_CPU_CLK) &&
+           (index == CCLK_SRC_PLLP_OUT0 || index == CCLK_SRC_PLLP_OUT4))
+               tegra_clk_set_pllp_out_cpu(true);
+
        val &= ~((super_state_to_src_mask(mux)) << shift);
        val |= (index & (super_state_to_src_mask(mux))) << shift;
 
        writel_relaxed(val, mux->reg);
        udelay(2);
 
+       /* disable PLLP branches to CPU if not used */
+       if ((mux->flags & TEGRA210_CPU_CLK) &&
+           index != CCLK_SRC_PLLP_OUT0 && index != CCLK_SRC_PLLP_OUT4)
+               tegra_clk_set_pllp_out_cpu(false);
+
 out:
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
index cdfe7c9697e1500ce1c78f2e261d42773e625852..5760c978bef7cb1d3073278e0c6e877c6c172ccf 100644 (file)
@@ -180,7 +180,7 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
                                        gen_info->num_cclk_g_parents,
                                        CLK_SET_RATE_PARENT,
                                        clk_base + CCLKG_BURST_POLICY,
-                                       0, 4, 8, 0, NULL);
+                                       TEGRA210_CPU_CLK, 4, 8, 0, NULL);
                } else {
                        clk = tegra_clk_register_super_mux("cclk_g",
                                        gen_info->cclk_g_parents,
@@ -196,6 +196,11 @@ static void __init tegra_super_clk_init(void __iomem *clk_base,
        dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
        if (dt_clk) {
                if (gen_info->gen == gen5) {
+                       /*
+                        * TEGRA210_CPU_CLK flag is not needed for cclk_lp as
+                        * cluster switching is not currently supported on
+                        * Tegra210 and also cpu_lp is not used.
+                        */
                        clk = tegra_clk_register_super_mux("cclk_lp",
                                        gen_info->cclk_lp_parents,
                                        gen_info->num_cclk_lp_parents,
index 573e3c967ae149d7597709c35e4977388f491519..eb08047fd02ffc907e96943575524a35c7e3cadc 100644 (file)
@@ -23,6 +23,7 @@
 #define CLK_OUT_ENB_W                  0x364
 #define CLK_OUT_ENB_X                  0x280
 #define CLK_OUT_ENB_Y                  0x298
+#define CLK_ENB_PLLP_OUT_CPU           BIT(31)
 #define CLK_OUT_ENB_SET_L              0x320
 #define CLK_OUT_ENB_CLR_L              0x324
 #define CLK_OUT_ENB_SET_H              0x328
@@ -199,6 +200,19 @@ const struct tegra_clk_periph_regs *get_reg_bank(int clkid)
        }
 }
 
+void tegra_clk_set_pllp_out_cpu(bool enable)
+{
+       u32 val;
+
+       val = readl_relaxed(clk_base + CLK_OUT_ENB_Y);
+       if (enable)
+               val |= CLK_ENB_PLLP_OUT_CPU;
+       else
+               val &= ~CLK_ENB_PLLP_OUT_CPU;
+
+       writel_relaxed(val, clk_base + CLK_OUT_ENB_Y);
+}
+
 struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks)
 {
        clk_base = regs;
index 7c956ce521d610cf2e28fef6b95955179e598ac3..21bb0f24c6c1d728af6547322d80047a5c3900c0 100644 (file)
@@ -669,6 +669,9 @@ struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
  * Flags:
  * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
  *     that this is LP cluster clock.
+ * TEGRA210_CPU_CLK - This flag is used to identify CPU cluster for gen5
+ * super mux parent using PLLP branches. To use PLLP branches to CPU, need
+ * to configure additional bit PLLP_OUT_CPU in the clock registers.
  */
 struct tegra_clk_super_mux {
        struct clk_hw   hw;
@@ -685,6 +688,7 @@ struct tegra_clk_super_mux {
 #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
 
 #define TEGRA_DIVIDER_2 BIT(0)
+#define TEGRA210_CPU_CLK BIT(1)
 
 extern const struct clk_ops tegra_clk_super_ops;
 struct clk *tegra_clk_register_super_mux(const char *name,
@@ -830,6 +834,7 @@ int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div);
 int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width,
                 u8 frac_width, u8 flags);
 void tegra_clk_osc_resume(void __iomem *clk_base);
+void tegra_clk_set_pllp_out_cpu(bool enable);
 
 
 /* Combined read fence with delay */