diff mbox series

[v1,1/3] clk: tegra: Convert CCLKG mux to mux + clock divider on Tegra30

Message ID 20180830192045.11017-2-digetx@gmail.com (mailing list archive)
State Changes Requested, archived
Headers show
Series CPU clock changes for Tegra20/30 | expand

Commit Message

Dmitry Osipenko Aug. 30, 2018, 7:20 p.m. UTC
Some of the CCLKG parents aren't accessible via device tree because they
are created as non-DT clocks. Apparently there is no reason to define
these clocks in that manner, hence convert CCLKG mux to mux + clock
divider to remove the non-DT parent clocks. Now it is possible to request
all of CCLKG parents from device tree, which is necessary for the CPUFreq
driver.

Note that CCLKG bypasses clock divider only if PLLX is selected as the
parent, hence previous CCLKG parents definition was incorrect.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/clk/tegra/clk-super.c    | 16 +++++++++++++-
 drivers/clk/tegra/clk-tegra210.c |  2 +-
 drivers/clk/tegra/clk-tegra30.c  | 38 +++++---------------------------
 drivers/clk/tegra/clk.h          |  9 ++++++--
 4 files changed, 28 insertions(+), 37 deletions(-)

Comments

Jon Hunter Oct. 17, 2018, 8:53 a.m. UTC | #1
On 30/08/2018 20:20, Dmitry Osipenko wrote:
> Some of the CCLKG parents aren't accessible via device tree because they
> are created as non-DT clocks. Apparently there is no reason to define
> these clocks in that manner, hence convert CCLKG mux to mux + clock
> divider to remove the non-DT parent clocks. Now it is possible to request
> all of CCLKG parents from device tree, which is necessary for the CPUFreq
> driver.

Is it likely that all of these clock parents will be used by the CPUFreq
driver for these devices? If the clocks you currently need are available
then my preference would be to stick with what we have for now.

Cheers
Jon
Dmitry Osipenko Oct. 17, 2018, 12:27 p.m. UTC | #2
On 10/17/18 11:53 AM, Jon Hunter wrote:
> 
> On 30/08/2018 20:20, Dmitry Osipenko wrote:
>> Some of the CCLKG parents aren't accessible via device tree because they
>> are created as non-DT clocks. Apparently there is no reason to define
>> these clocks in that manner, hence convert CCLKG mux to mux + clock
>> divider to remove the non-DT parent clocks. Now it is possible to request
>> all of CCLKG parents from device tree, which is necessary for the CPUFreq
>> driver.
> 
> Is it likely that all of these clock parents will be used by the CPUFreq
> driver for these devices? If the clocks you currently need are available
> then my preference would be to stick with what we have for now.

You could use them all if you want, that's what HW allow. The current clock description doesn't fully describe the HW, though it should be enough at least for the CPUFreq driver if we are going to use clk_get_sys() and stick to the "default" parent. Peter?
diff mbox series

Patch

diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
index 84267cfc4433..8ba58f7942d9 100644
--- a/drivers/clk/tegra/clk-super.c
+++ b/drivers/clk/tegra/clk-super.c
@@ -65,6 +65,8 @@  static u8 clk_super_get_parent(struct clk_hw *hw)
 	    (source == mux->pllx_index))
 		source = mux->div2_index;
 
+	mux->pllx_parent = (source == mux->pllx_index);
+
 	return source;
 }
 
@@ -114,6 +116,8 @@  static int clk_super_set_parent(struct clk_hw *hw, u8 index)
 	writel_relaxed(val, mux->reg);
 	udelay(2);
 
+	mux->pllx_parent = (index == mux->pllx_index);
+
 out:
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
@@ -132,6 +136,9 @@  static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate,
 	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
 	struct clk_hw *div_hw = &super->frac_div.hw;
 
+	if ((super->flags & TEGRA_CCLKG_DIVIDER) && super->pllx_parent)
+		return *parent_rate;
+
 	__clk_hw_set_clk(div_hw, hw);
 
 	return super->div_ops->round_rate(div_hw, rate, parent_rate);
@@ -143,6 +150,9 @@  static unsigned long clk_super_recalc_rate(struct clk_hw *hw,
 	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
 	struct clk_hw *div_hw = &super->frac_div.hw;
 
+	if ((super->flags & TEGRA_CCLKG_DIVIDER) && super->pllx_parent)
+		return parent_rate;
+
 	__clk_hw_set_clk(div_hw, hw);
 
 	return super->div_ops->recalc_rate(div_hw, parent_rate);
@@ -154,6 +164,9 @@  static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,
 	struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
 	struct clk_hw *div_hw = &super->frac_div.hw;
 
+	if ((super->flags & TEGRA_CCLKG_DIVIDER) && super->pllx_parent)
+		return 0;
+
 	__clk_hw_set_clk(div_hw, hw);
 
 	return super->div_ops->set_rate(div_hw, rate, parent_rate);
@@ -204,7 +217,7 @@  struct clk *tegra_clk_register_super_mux(const char *name,
 }
 
 struct clk *tegra_clk_register_super_clk(const char *name,
-		const char * const *parent_names, u8 num_parents,
+		const char * const *parent_names, u8 num_parents, u8 pllx_index,
 		unsigned long flags, void __iomem *reg, u8 clk_super_flags,
 		spinlock_t *lock)
 {
@@ -232,6 +245,7 @@  struct clk *tegra_clk_register_super_clk(const char *name,
 	super->frac_div.frac_width = 1;
 	super->frac_div.lock = lock;
 	super->div_ops = &tegra_clk_frac_div_ops;
+	super->pllx_index = pllx_index;
 
 	/* Data in .init is copied by clk_register(), so stack variable OK */
 	super->hw.init = &init;
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 9eb1cb14fce1..990c8773e50c 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -3026,7 +3026,7 @@  static __init void tegra210_periph_clk_init(void __iomem *clk_base,
 	clks[TEGRA210_CLK_CML1] = clk;
 
 	clk = tegra_clk_register_super_clk("aclk", aclk_parents,
-				ARRAY_SIZE(aclk_parents), 0, clk_base + 0x6e0,
+				ARRAY_SIZE(aclk_parents), 0, 0, clk_base + 0x6e0,
 				0, NULL);
 	clks[TEGRA210_CLK_ACLK] = clk;
 
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index acfe661b2ae7..c4b78316ba8a 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -902,8 +902,8 @@  static void __init tegra30_pll_init(void)
 }
 
 static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
-					"pll_p_cclkg", "pll_p_out4_cclkg",
-					"pll_p_out3_cclkg", "unused", "pll_x" };
+					"pll_p", "pll_p_out4", "pll_p_out3",
+					"unused", "pll_x" };
 static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
 					 "pll_p_cclklp", "pll_p_out4_cclklp",
 					 "pll_p_out3_cclklp", "unused", "pll_x",
@@ -916,39 +916,11 @@  static void __init tegra30_super_clk_init(void)
 {
 	struct clk *clk;
 
-	/*
-	 * Clock input to cclk_g divided from pll_p using
-	 * U71 divider of cclk_g.
-	 */
-	clk = tegra_clk_register_divider("pll_p_cclkg", "pll_p",
-				clk_base + SUPER_CCLKG_DIVIDER, 0,
-				TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
-	clk_register_clkdev(clk, "pll_p_cclkg", NULL);
-
-	/*
-	 * Clock input to cclk_g divided from pll_p_out3 using
-	 * U71 divider of cclk_g.
-	 */
-	clk = tegra_clk_register_divider("pll_p_out3_cclkg", "pll_p_out3",
-				clk_base + SUPER_CCLKG_DIVIDER, 0,
-				TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
-	clk_register_clkdev(clk, "pll_p_out3_cclkg", NULL);
-
-	/*
-	 * Clock input to cclk_g divided from pll_p_out4 using
-	 * U71 divider of cclk_g.
-	 */
-	clk = tegra_clk_register_divider("pll_p_out4_cclkg", "pll_p_out4",
-				clk_base + SUPER_CCLKG_DIVIDER, 0,
-				TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
-	clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL);
-
 	/* CCLKG */
-	clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
-				  ARRAY_SIZE(cclk_g_parents),
-				  CLK_SET_RATE_PARENT,
+	clk = tegra_clk_register_super_clk("cclk_g", cclk_g_parents,
+				  ARRAY_SIZE(cclk_g_parents), 8, 0,
 				  clk_base + CCLKG_BURST_POLICY,
-				  0, 4, 0, 0, NULL);
+				  TEGRA_CCLKG_DIVIDER, NULL);
 	clks[TEGRA30_CLK_CCLK_G] = clk;
 
 	/*
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index d2c3a010f8e9..64922f0f5fdd 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -680,6 +680,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.
+ *
+ * TEGRA_CCLKG_DIVIDER - G cluster clock may bypass clocks divider. This flag
+ *     indicates that this is G cluster clock.
  */
 struct tegra_clk_super_mux {
 	struct clk_hw	hw;
@@ -691,11 +694,13 @@  struct tegra_clk_super_mux {
 	u8		div2_index;
 	u8		pllx_index;
 	spinlock_t	*lock;
+	bool		pllx_parent;
 };
 
 #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
 
-#define TEGRA_DIVIDER_2 BIT(0)
+#define TEGRA_DIVIDER_2		BIT(0)
+#define TEGRA_CCLKG_DIVIDER	BIT(1)
 
 extern const struct clk_ops tegra_clk_super_ops;
 struct clk *tegra_clk_register_super_mux(const char *name,
@@ -703,7 +708,7 @@  struct clk *tegra_clk_register_super_mux(const char *name,
 		unsigned long flags, void __iomem *reg, u8 clk_super_flags,
 		u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock);
 struct clk *tegra_clk_register_super_clk(const char *name,
-		const char * const *parent_names, u8 num_parents,
+		const char * const *parent_names, u8 num_parents, u8 pllx_index,
 		unsigned long flags, void __iomem *reg, u8 clk_super_flags,
 		spinlock_t *lock);