diff mbox series

[v2,04/17] clk: mmp2: Add support for PLL clock sources

Message ID 20200309194254.29009-5-lkundrak@v3.sk (mailing list archive)
State Accepted, archived
Headers show
Series clk: mmp2: MMP2 CLK Update | expand

Commit Message

Lubomir Rintel March 9, 2020, 7:42 p.m. UTC
The clk-of-mmp2 driver pretends that the clock outputs from the PLLs are
constant, but in fact they are configurable.

Add logic for obtaining the actual clock rates on MMP2 as well as MMP3.
There is no documentation for either SoC, but the "systemsetting" drivers
from Marvell GPL code dump provide some clue as far as MPMU registers on
MMP2 [1] and MMP3 [2] go.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp2_systemsetting.c
[2] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp3_systemsetting.c

A separate commit will adjust the clk-of-mmp2 driver.

Tested on a MMP3-based Dell Wyse 3020 as well as MMP2-based OLPC
XO-1.75 laptop.

Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
 drivers/clk/mmp/Makefile  |   2 +-
 drivers/clk/mmp/clk-pll.c | 139 ++++++++++++++++++++++++++++++++++++++
 drivers/clk/mmp/clk.c     |  31 +++++++++
 drivers/clk/mmp/clk.h     |  24 +++++++
 4 files changed, 195 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mmp/clk-pll.c

Comments

Stephen Boyd March 21, 2020, 1:24 a.m. UTC | #1
Quoting Lubomir Rintel (2020-03-09 12:42:41)
> The clk-of-mmp2 driver pretends that the clock outputs from the PLLs are
> constant, but in fact they are configurable.
> 
> Add logic for obtaining the actual clock rates on MMP2 as well as MMP3.
> There is no documentation for either SoC, but the "systemsetting" drivers
> from Marvell GPL code dump provide some clue as far as MPMU registers on
> MMP2 [1] and MMP3 [2] go.
> 
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp2_systemsetting.c
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp3_systemsetting.c
> 
> A separate commit will adjust the clk-of-mmp2 driver.
> 
> Tested on a MMP3-based Dell Wyse 3020 as well as MMP2-based OLPC
> XO-1.75 laptop.
> 
> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> ---

Applied to clk-next
Guenter Roeck April 6, 2020, 7:30 p.m. UTC | #2
On Mon, Mar 09, 2020 at 08:42:41PM +0100, Lubomir Rintel wrote:
> The clk-of-mmp2 driver pretends that the clock outputs from the PLLs are
> constant, but in fact they are configurable.
> 
> Add logic for obtaining the actual clock rates on MMP2 as well as MMP3.
> There is no documentation for either SoC, but the "systemsetting" drivers
> from Marvell GPL code dump provide some clue as far as MPMU registers on
> MMP2 [1] and MMP3 [2] go.
> 
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp2_systemsetting.c
> [2] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp3_systemsetting.c
> 
> A separate commit will adjust the clk-of-mmp2 driver.
> 
> Tested on a MMP3-based Dell Wyse 3020 as well as MMP2-based OLPC
> XO-1.75 laptop.
> 
> Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>

This patch results in:

arm-linux-gnueabi-ld: drivers/clk/mmp/clk.o: in function `mmp_register_pll_clks':
drivers/clk/mmp/clk.c:192: undefined reference to `mmp_clk_register_pll'

when building arm:pxa910_defconfig.

Bisect log is attached.

Guenter

---
# bad: [a10c9c710f9ecea87b9f4bbb837467893b4bef01] Merge tag 'for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
# good: [4c205c84e249e0a91dcfabe461d77667ec9b2d05] Merge tag 'keys-fixes-20200329' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
git bisect start 'a10c9c710f9e' '4c205c84e249'
# bad: [31c0aa87ec8a30b1e9e4cf862905a369560f7705] Merge tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random
git bisect bad 31c0aa87ec8a30b1e9e4cf862905a369560f7705
# bad: [53a2cc5cc36fd97728e1b418dbfa8f70bf23391a] Merge branches 'clk-ti', 'clk-ingenic', 'clk-typo', 'clk-at91', 'clk-mmp2' and 'clk-arm-icst' into clk-next
git bisect bad 53a2cc5cc36fd97728e1b418dbfa8f70bf23391a
# good: [2d11e9a1fd2abe784b334442b36f7d83ff914287] Merge branches 'clk-phase-errors', 'clk-amlogic', 'clk-renesas' and 'clk-allwinner' into clk-next
git bisect good 2d11e9a1fd2abe784b334442b36f7d83ff914287
# bad: [de17be999cb07effacf6a1129602f63396f5af27] clk: mmp2: Fix bit masks for LCDC I/O and pixel clocks
git bisect bad de17be999cb07effacf6a1129602f63396f5af27
# bad: [4d6da655d1871fadcb2b5de086e5a35883e22c95] dt-bindings: marvell,mmp2: Add clock ids for MMP3 PLLs
git bisect bad 4d6da655d1871fadcb2b5de086e5a35883e22c95
# bad: [5d34d0b32d6c13947b0aa890fc4c68f203491169] clk: mmp2: Add support for PLL clock sources
git bisect bad 5d34d0b32d6c13947b0aa890fc4c68f203491169
# good: [cb8dbfe831758fb2ba52d8c30db5249e48f57b8b] clk: mmp2: Constify some strings
git bisect good cb8dbfe831758fb2ba52d8c30db5249e48f57b8b
# good: [7de0b8b8b0508af5fed2f2a07e3abb6acac0c466] dt-bindings: clock: Convert marvell,mmp2-clock to json-schema
git bisect good 7de0b8b8b0508af5fed2f2a07e3abb6acac0c466
# first bad commit: [5d34d0b32d6c13947b0aa890fc4c68f203491169] clk: mmp2: Add support for PLL clock sources
Stephen Boyd April 9, 2020, 8:32 a.m. UTC | #3
Quoting Guenter Roeck (2020-04-06 12:30:50)
> On Mon, Mar 09, 2020 at 08:42:41PM +0100, Lubomir Rintel wrote:
> > The clk-of-mmp2 driver pretends that the clock outputs from the PLLs are
> > constant, but in fact they are configurable.
> > 
> > Add logic for obtaining the actual clock rates on MMP2 as well as MMP3.
> > There is no documentation for either SoC, but the "systemsetting" drivers
> > from Marvell GPL code dump provide some clue as far as MPMU registers on
> > MMP2 [1] and MMP3 [2] go.
> > 
> > [1] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp2_systemsetting.c
> > [2] https://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/linux-mmp3-dell-ariel.git/tree/drivers/char/mmp3_systemsetting.c
> > 
> > A separate commit will adjust the clk-of-mmp2 driver.
> > 
> > Tested on a MMP3-based Dell Wyse 3020 as well as MMP2-based OLPC
> > XO-1.75 laptop.
> > 
> > Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> 
> This patch results in:
> 
> arm-linux-gnueabi-ld: drivers/clk/mmp/clk.o: in function `mmp_register_pll_clks':
> drivers/clk/mmp/clk.c:192: undefined reference to `mmp_clk_register_pll'
> 
> when building arm:pxa910_defconfig.
> 

Thanks. I see that Arnd has sent a fix for this.

https://lore.kernel.org/r/20200408160518.2798571-1-arnd@arndb.de
diff mbox series

Patch

diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index acc141adf087c..14dc8a8a9d087 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -8,7 +8,7 @@  obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
 obj-$(CONFIG_RESET_CONTROLLER) += reset.o
 
 obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o
-obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o
+obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-pll.c b/drivers/clk/mmp/clk-pll.c
new file mode 100644
index 0000000000000..7077be2938711
--- /dev/null
+++ b/drivers/clk/mmp/clk-pll.c
@@ -0,0 +1,139 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MMP PLL clock rate calculation
+ *
+ * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include "clk.h"
+
+#define to_clk_mmp_pll(hw)	container_of(hw, struct mmp_clk_pll, hw)
+
+struct mmp_clk_pll {
+	struct clk_hw hw;
+	unsigned long default_rate;
+	void __iomem *enable_reg;
+	u32 enable;
+	void __iomem *reg;
+	u8 shift;
+
+	unsigned long input_rate;
+	void __iomem *postdiv_reg;
+	u8 postdiv_shift;
+};
+
+static int mmp_clk_pll_is_enabled(struct clk_hw *hw)
+{
+	struct mmp_clk_pll *pll = to_clk_mmp_pll(hw);
+	u32 val;
+
+	val = readl_relaxed(pll->enable_reg);
+	if ((val & pll->enable) == pll->enable)
+		return 1;
+
+	/* Some PLLs, if not software controlled, output default clock. */
+	if (pll->default_rate > 0)
+		return 1;
+
+	return 0;
+}
+
+static unsigned long mmp_clk_pll_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct mmp_clk_pll *pll = to_clk_mmp_pll(hw);
+	u32 fbdiv, refdiv, postdiv;
+	u64 rate;
+	u32 val;
+
+	val = readl_relaxed(pll->enable_reg);
+	if ((val & pll->enable) != pll->enable)
+		return pll->default_rate;
+
+	if (pll->reg) {
+		val = readl_relaxed(pll->reg);
+		fbdiv = (val >> pll->shift) & 0x1ff;
+		refdiv = (val >> (pll->shift + 9)) & 0x1f;
+	} else {
+		fbdiv = 2;
+		refdiv = 1;
+	}
+
+	if (pll->postdiv_reg) {
+		/* MMP3 clock rate calculation */
+		static const u8 postdivs[] = {2, 3, 4, 5, 6, 8, 10, 12, 16};
+
+		val = readl_relaxed(pll->postdiv_reg);
+		postdiv = (val >> pll->postdiv_shift) & 0x7;
+
+		rate = pll->input_rate;
+		rate *= 2 * fbdiv;
+		do_div(rate, refdiv);
+		do_div(rate, postdivs[postdiv]);
+	} else {
+		/* MMP2 clock rate calculation */
+		if (refdiv == 3) {
+			rate = 19200000;
+		} else if (refdiv == 4) {
+			rate = 26000000;
+		} else {
+			pr_err("bad refdiv: %d (0x%08x)\n", refdiv, val);
+			return 0;
+		}
+
+		rate *= fbdiv + 2;
+		do_div(rate, refdiv + 2);
+	}
+
+	return (unsigned long)rate;
+}
+
+static const struct clk_ops mmp_clk_pll_ops = {
+	.is_enabled = mmp_clk_pll_is_enabled,
+	.recalc_rate = mmp_clk_pll_recalc_rate,
+};
+
+struct clk *mmp_clk_register_pll(char *name,
+			unsigned long default_rate,
+			void __iomem *enable_reg, u32 enable,
+			void __iomem *reg, u8 shift,
+			unsigned long input_rate,
+			void __iomem *postdiv_reg, u8 postdiv_shift)
+{
+	struct mmp_clk_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &mmp_clk_pll_ops;
+	init.flags = 0;
+	init.parent_names = NULL;
+	init.num_parents = 0;
+
+	pll->default_rate = default_rate;
+	pll->enable_reg = enable_reg;
+	pll->enable = enable;
+	pll->reg = reg;
+	pll->shift = shift;
+
+	pll->input_rate = input_rate;
+	pll->postdiv_reg = postdiv_reg;
+	pll->postdiv_shift = postdiv_shift;
+
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c
index ca7d37e2c7be6..317123641d1ed 100644
--- a/drivers/clk/mmp/clk.c
+++ b/drivers/clk/mmp/clk.c
@@ -176,6 +176,37 @@  void mmp_register_div_clks(struct mmp_clk_unit *unit,
 	}
 }
 
+void mmp_register_pll_clks(struct mmp_clk_unit *unit,
+			struct mmp_param_pll_clk *clks,
+			void __iomem *base, int size)
+{
+	struct clk *clk;
+	int i;
+
+	for (i = 0; i < size; i++) {
+		void __iomem *reg = NULL;
+
+		if (clks[i].offset)
+			reg = base + clks[i].offset;
+
+		clk = mmp_clk_register_pll(clks[i].name,
+					clks[i].default_rate,
+					base + clks[i].enable_offset,
+					clks[i].enable,
+					reg, clks[i].shift,
+					clks[i].input_rate,
+					base + clks[i].postdiv_offset,
+					clks[i].postdiv_shift);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+		if (clks[i].id)
+			unit->clk_table[clks[i].id] = clk;
+	}
+}
+
 void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
 			struct clk *clk)
 {
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 37d1e1d7b664c..971b4d6d992fb 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -221,6 +221,30 @@  void mmp_register_div_clks(struct mmp_clk_unit *unit,
 			struct mmp_param_div_clk *clks,
 			void __iomem *base, int size);
 
+struct mmp_param_pll_clk {
+	unsigned int id;
+	char *name;
+	unsigned long default_rate;
+	unsigned long enable_offset;
+	u32 enable;
+	unsigned long offset;
+	u8 shift;
+	/* MMP3 specific: */
+	unsigned long input_rate;
+	unsigned long postdiv_offset;
+	unsigned long postdiv_shift;
+};
+void mmp_register_pll_clks(struct mmp_clk_unit *unit,
+			struct mmp_param_pll_clk *clks,
+			void __iomem *base, int size);
+
+extern struct clk *mmp_clk_register_pll(char *name,
+			unsigned long default_rate,
+			void __iomem *enable_reg, u32 enable,
+			void __iomem *reg, u8 shift,
+			unsigned long input_rate,
+			void __iomem *postdiv_reg, u8 postdiv_shift);
+
 #define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc)	\
 {							\
 	.width_div = (w_d),				\