linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] clk: Ingenic JZ4760(B) support
@ 2021-03-07 14:17 Paul Cercueil
  2021-03-07 14:17 ` [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles Paul Cercueil
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

Hi,

Here are a set of patches to add support for the Ingenic JZ4760(B) SoCs.

One thing to note is that the ingenic,jz4760-tcu is undocumented for now,
as I will update the TCU documentation in a different patchset.

Zhou: the CGU code now supports overriding the PLL M/N/OD calc
algorithm, please tell me if it works for you.

Cheers,
-Paul

Paul Cercueil (6):
  dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
  clk: Support bypassing dividers
  clk: ingenic: Read bypass register only when there is one
  clk: ingenic: Remove pll_info.no_bypass_bit
  clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
  clk: ingenic: Add support for the JZ4760

 .../bindings/clock/ingenic,cgu.yaml           |   4 +
 drivers/clk/ingenic/Kconfig                   |  10 +
 drivers/clk/ingenic/Makefile                  |   1 +
 drivers/clk/ingenic/cgu.c                     |  92 ++--
 drivers/clk/ingenic/cgu.h                     |  12 +-
 drivers/clk/ingenic/jz4725b-cgu.c             |  12 +-
 drivers/clk/ingenic/jz4740-cgu.c              |  12 +-
 drivers/clk/ingenic/jz4760-cgu.c              | 433 ++++++++++++++++++
 drivers/clk/ingenic/jz4770-cgu.c              |  15 +-
 drivers/clk/ingenic/tcu.c                     |   2 +
 include/dt-bindings/clock/jz4760-cgu.h        |  54 +++
 11 files changed, 591 insertions(+), 56 deletions(-)
 create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
 create mode 100644 include/dt-bindings/clock/jz4760-cgu.h

-- 
2.30.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-08 22:56   ` Rob Herring
  2021-03-07 14:17 ` [PATCH 2/6] clk: Support bypassing dividers Paul Cercueil
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

Add ingenic,jz4760-cgu and ingenic,jz4760b-cgu compatible strings for
the JZ4760 and JZ4760B SoCs respectively.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 Documentation/devicetree/bindings/clock/ingenic,cgu.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml
index c65b9458c0b6..6d6236e02c22 100644
--- a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml
+++ b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml
@@ -22,6 +22,8 @@ select:
         enum:
           - ingenic,jz4740-cgu
           - ingenic,jz4725b-cgu
+          - ingenic,jz4760-cgu
+          - ingenic,jz4760b-cgu
           - ingenic,jz4770-cgu
           - ingenic,jz4780-cgu
           - ingenic,x1000-cgu
@@ -49,6 +51,8 @@ properties:
       - enum:
           - ingenic,jz4740-cgu
           - ingenic,jz4725b-cgu
+          - ingenic,jz4760-cgu
+          - ingenic,jz4760b-cgu
           - ingenic,jz4770-cgu
           - ingenic,jz4780-cgu
           - ingenic,x1000-cgu
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/6] clk: Support bypassing dividers
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
  2021-03-07 14:17 ` [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-07 14:17 ` [PATCH 3/6] clk: ingenic: Read bypass register only when there is one Paul Cercueil
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

When a clock is declared as both CGU_CLK_DIV and CGU_CLK_MUX, the CGU
code expects the mux to be applied first, the divider second.

On the JZ4760, and maybe on some other SoCs, some clocks also have a mux
setting and a divider, but the divider is not applied to all parents
selectable from the mux.

This could be solved by creating two clocks, one with CGU_CLK_DIV and
one with CGU_CLK_MUX, but that would increase the number of clocks.

Instead, add a 8-bit mask to CGU_CLK_DIV clocks. If the bit
corresponding to the parent clock's index is set, the divider is
bypassed.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clk/ingenic/cgu.c         | 33 ++++++++++++++++++++-----------
 drivers/clk/ingenic/cgu.h         |  2 ++
 drivers/clk/ingenic/jz4725b-cgu.c | 12 +++++------
 drivers/clk/ingenic/jz4740-cgu.c  | 12 +++++------
 drivers/clk/ingenic/jz4770-cgu.c  | 12 +++++------
 5 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index c8e9cb6c8e39..0619d45a950c 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -369,18 +369,23 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 	struct ingenic_cgu *cgu = ingenic_clk->cgu;
 	unsigned long rate = parent_rate;
 	u32 div_reg, div;
+	u8 parent;
 
 	if (clk_info->type & CGU_CLK_DIV) {
-		div_reg = readl(cgu->base + clk_info->div.reg);
-		div = (div_reg >> clk_info->div.shift) &
-		      GENMASK(clk_info->div.bits - 1, 0);
+		parent = ingenic_clk_get_parent(hw);
 
-		if (clk_info->div.div_table)
-			div = clk_info->div.div_table[div];
-		else
-			div = (div + 1) * clk_info->div.div;
+		if (!(clk_info->div.bypass_mask & BIT(parent))) {
+			div_reg = readl(cgu->base + clk_info->div.reg);
+			div = (div_reg >> clk_info->div.shift) &
+			      GENMASK(clk_info->div.bits - 1, 0);
+
+			if (clk_info->div.div_table)
+				div = clk_info->div.div_table[div];
+			else
+				div = (div + 1) * clk_info->div.div;
 
-		rate /= div;
+			rate /= div;
+		}
 	} else if (clk_info->type & CGU_CLK_FIXDIV) {
 		rate /= clk_info->fixdiv.div;
 	}
@@ -410,10 +415,16 @@ ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
 }
 
 static unsigned
-ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
+ingenic_clk_calc_div(struct clk_hw *hw,
+		     const struct ingenic_cgu_clk_info *clk_info,
 		     unsigned long parent_rate, unsigned long req_rate)
 {
 	unsigned int div, hw_div;
+	u8 parent;
+
+	parent = ingenic_clk_get_parent(hw);
+	if (clk_info->div.bypass_mask & BIT(parent))
+		return 1;
 
 	/* calculate the divide */
 	div = DIV_ROUND_UP(parent_rate, req_rate);
@@ -448,7 +459,7 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
 	unsigned int div = 1;
 
 	if (clk_info->type & CGU_CLK_DIV)
-		div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+		div = ingenic_clk_calc_div(hw, clk_info, *parent_rate, req_rate);
 	else if (clk_info->type & CGU_CLK_FIXDIV)
 		div = clk_info->fixdiv.div;
 	else if (clk_hw_can_set_rate_parent(hw))
@@ -480,7 +491,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
 	int ret = 0;
 
 	if (clk_info->type & CGU_CLK_DIV) {
-		div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
+		div = ingenic_clk_calc_div(hw, clk_info, parent_rate, req_rate);
 		rate = DIV_ROUND_UP(parent_rate, div);
 
 		if (rate != req_rate)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 2c75ef4a36f5..44d97a259692 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -84,6 +84,7 @@ struct ingenic_cgu_mux_info {
  *          isn't one
  * @busy_bit: the index of the busy bit within reg, or -1 if there isn't one
  * @stop_bit: the index of the stop bit within reg, or -1 if there isn't one
+ * @bypass_mask: mask of parent clocks for which the divider does not apply
  * @div_table: optional table to map the value read from the register to the
  *             actual divider value
  */
@@ -95,6 +96,7 @@ struct ingenic_cgu_div_info {
 	s8 ce_bit;
 	s8 busy_bit;
 	s8 stop_bit;
+	u8 bypass_mask;
 	const u8 *div_table;
 };
 
diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c
index 8c38e72d14a7..5154b0cf8ad6 100644
--- a/drivers/clk/ingenic/jz4725b-cgu.c
+++ b/drivers/clk/ingenic/jz4725b-cgu.c
@@ -80,7 +80,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"pll half", CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
 			jz4725b_cgu_pll_half_div_table,
 		},
 	},
@@ -89,7 +89,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"cclk", CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
 			jz4725b_cgu_cpccr_div_table,
 		},
 	},
@@ -98,7 +98,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"hclk", CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
 			jz4725b_cgu_cpccr_div_table,
 		},
 	},
@@ -107,7 +107,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"pclk", CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
 			jz4725b_cgu_cpccr_div_table,
 		},
 	},
@@ -116,7 +116,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"mclk", CGU_CLK_DIV,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
 			jz4725b_cgu_cpccr_div_table,
 		},
 	},
@@ -125,7 +125,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
 		"ipu", CGU_CLK_DIV | CGU_CLK_GATE,
 		.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
 			jz4725b_cgu_cpccr_div_table,
 		},
 		.gate = { CGU_REG_CLKGR, 13 },
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index c0ac9196a581..cd878f08aca3 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -95,7 +95,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"pll half", CGU_CLK_DIV,
 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+			CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
 			jz4740_cgu_pll_half_div_table,
 		},
 	},
@@ -104,7 +104,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"cclk", CGU_CLK_DIV,
 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
 			jz4740_cgu_cpccr_div_table,
 		},
 	},
@@ -113,7 +113,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"hclk", CGU_CLK_DIV,
 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
 			jz4740_cgu_cpccr_div_table,
 		},
 	},
@@ -122,7 +122,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"pclk", CGU_CLK_DIV,
 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
 			jz4740_cgu_cpccr_div_table,
 		},
 	},
@@ -131,7 +131,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"mclk", CGU_CLK_DIV,
 		.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
 			jz4740_cgu_cpccr_div_table,
 		},
 	},
@@ -140,7 +140,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
 		"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
 		.parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 },
 		.div = {
-			CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1,
+			CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1, 0,
 			jz4740_cgu_cpccr_div_table,
 		},
 		.gate = { CGU_REG_CLKGR, 10 },
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
index 9ea4490ecb7f..381a27f20b51 100644
--- a/drivers/clk/ingenic/jz4770-cgu.c
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -152,7 +152,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"cclk", CGU_CLK_DIV,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 	},
@@ -160,7 +160,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"h0clk", CGU_CLK_DIV,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 	},
@@ -168,7 +168,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 		.gate = { CGU_REG_CLKGR1, 7 },
@@ -177,7 +177,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"h2clk", CGU_CLK_DIV,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 	},
@@ -185,7 +185,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 		.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
@@ -194,7 +194,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 		"pclk", CGU_CLK_DIV,
 		.parents = { JZ4770_CLK_PLL0, },
 		.div = {
-			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
 			jz4770_cgu_cpccr_div_table,
 		},
 	},
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/6] clk: ingenic: Read bypass register only when there is one
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
  2021-03-07 14:17 ` [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles Paul Cercueil
  2021-03-07 14:17 ` [PATCH 2/6] clk: Support bypassing dividers Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-07 14:17 ` [PATCH 4/6] clk: ingenic: Remove pll_info.no_bypass_bit Paul Cercueil
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

Rework the clock code so that the bypass register is only read when
there is actually a bypass functionality.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clk/ingenic/cgu.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 0619d45a950c..7686072aff8f 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -99,13 +99,14 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 	od_enc = ctl >> pll_info->od_shift;
 	od_enc &= GENMASK(pll_info->od_bits - 1, 0);
 
-	ctl = readl(cgu->base + pll_info->bypass_reg);
+	if (!pll_info->no_bypass_bit) {
+		ctl = readl(cgu->base + pll_info->bypass_reg);
 
-	bypass = !pll_info->no_bypass_bit &&
-		 !!(ctl & BIT(pll_info->bypass_bit));
+		bypass = !!(ctl & BIT(pll_info->bypass_bit));
 
-	if (bypass)
-		return parent_rate;
+		if (bypass)
+			return parent_rate;
+	}
 
 	for (od = 0; od < pll_info->od_max; od++) {
 		if (pll_info->od_encoding[od] == od_enc)
@@ -225,11 +226,13 @@ static int ingenic_pll_enable(struct clk_hw *hw)
 	u32 ctl;
 
 	spin_lock_irqsave(&cgu->lock, flags);
-	ctl = readl(cgu->base + pll_info->bypass_reg);
+	if (!pll_info->no_bypass_bit) {
+		ctl = readl(cgu->base + pll_info->bypass_reg);
 
-	ctl &= ~BIT(pll_info->bypass_bit);
+		ctl &= ~BIT(pll_info->bypass_bit);
 
-	writel(ctl, cgu->base + pll_info->bypass_reg);
+		writel(ctl, cgu->base + pll_info->bypass_reg);
+	}
 
 	ctl = readl(cgu->base + pll_info->reg);
 
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/6] clk: ingenic: Remove pll_info.no_bypass_bit
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (2 preceding siblings ...)
  2021-03-07 14:17 ` [PATCH 3/6] clk: ingenic: Read bypass register only when there is one Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-07 14:17 ` [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm Paul Cercueil
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

We can express that a PLL has no bypass bit by simply setting the
.bypass_bit field to a negative value.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clk/ingenic/cgu.c        | 4 ++--
 drivers/clk/ingenic/cgu.h        | 7 +++----
 drivers/clk/ingenic/jz4770-cgu.c | 3 +--
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 7686072aff8f..58f7ab5cf0fe 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -99,7 +99,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 	od_enc = ctl >> pll_info->od_shift;
 	od_enc &= GENMASK(pll_info->od_bits - 1, 0);
 
-	if (!pll_info->no_bypass_bit) {
+	if (pll_info->bypass_bit >= 0) {
 		ctl = readl(cgu->base + pll_info->bypass_reg);
 
 		bypass = !!(ctl & BIT(pll_info->bypass_bit));
@@ -226,7 +226,7 @@ static int ingenic_pll_enable(struct clk_hw *hw)
 	u32 ctl;
 
 	spin_lock_irqsave(&cgu->lock, flags);
-	if (!pll_info->no_bypass_bit) {
+	if (pll_info->bypass_bit >= 0) {
 		ctl = readl(cgu->base + pll_info->bypass_reg);
 
 		ctl &= ~BIT(pll_info->bypass_bit);
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 44d97a259692..10521d1b7b12 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -39,10 +39,10 @@
  *               their encoded values in the PLL control register, or -1 for
  *               unsupported values
  * @bypass_reg: the offset of the bypass control register within the CGU
- * @bypass_bit: the index of the bypass bit in the PLL control register
+ * @bypass_bit: the index of the bypass bit in the PLL control register, or
+ *              -1 if there is no bypass bit
  * @enable_bit: the index of the enable bit in the PLL control register
  * @stable_bit: the index of the stable bit in the PLL control register
- * @no_bypass_bit: if set, the PLL has no bypass functionality
  */
 struct ingenic_cgu_pll_info {
 	unsigned reg;
@@ -52,10 +52,9 @@ struct ingenic_cgu_pll_info {
 	u8 n_shift, n_bits, n_offset;
 	u8 od_shift, od_bits, od_max;
 	unsigned bypass_reg;
-	u8 bypass_bit;
+	s8 bypass_bit;
 	u8 enable_bit;
 	u8 stable_bit;
-	bool no_bypass_bit;
 };
 
 /**
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
index 381a27f20b51..2321742b3471 100644
--- a/drivers/clk/ingenic/jz4770-cgu.c
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -139,8 +139,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
 			.od_bits = 2,
 			.od_max = 8,
 			.od_encoding = pll_od_encoding,
-			.bypass_reg = CGU_REG_CPPCR1,
-			.no_bypass_bit = true,
+			.bypass_bit = -1,
 			.enable_bit = 7,
 			.stable_bit = 6,
 		},
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (3 preceding siblings ...)
  2021-03-07 14:17 ` [PATCH 4/6] clk: ingenic: Remove pll_info.no_bypass_bit Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-10 14:42   ` Zhou Yanjie
  2021-03-07 14:17 ` [PATCH 6/6] clk: ingenic: Add support for the JZ4760 Paul Cercueil
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

SoC-specific code can now provide a callback if they need to compute the
M/N/OD values in a specific way.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clk/ingenic/cgu.c | 40 ++++++++++++++++++++++++++-------------
 drivers/clk/ingenic/cgu.h |  3 +++
 2 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 58f7ab5cf0fe..266c7595d330 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -119,28 +119,42 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 		n * od);
 }
 
-static unsigned long
-ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
-		 unsigned long rate, unsigned long parent_rate,
-		 unsigned *pm, unsigned *pn, unsigned *pod)
+static void
+ingenic_pll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
+			unsigned long rate, unsigned long parent_rate,
+			unsigned int *pm, unsigned int *pn, unsigned int *pod)
 {
-	const struct ingenic_cgu_pll_info *pll_info;
-	unsigned m, n, od;
-
-	pll_info = &clk_info->pll;
-	od = 1;
+	unsigned int m, n, od = 1;
 
 	/*
 	 * The frequency after the input divider must be between 10 and 50 MHz.
 	 * The highest divider yields the best resolution.
 	 */
 	n = parent_rate / (10 * MHZ);
-	n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
-	n = max_t(unsigned, n, pll_info->n_offset);
+	n = min_t(unsigned int, n, 1 << pll_info->n_bits);
+	n = max_t(unsigned int, n, pll_info->n_offset);
 
 	m = (rate / MHZ) * od * n / (parent_rate / MHZ);
-	m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
-	m = max_t(unsigned, m, pll_info->m_offset);
+	m = min_t(unsigned int, m, 1 << pll_info->m_bits);
+	m = max_t(unsigned int, m, pll_info->m_offset);
+
+	*pm = m;
+	*pn = n;
+	*pod = od;
+}
+
+static unsigned long
+ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
+		 unsigned long rate, unsigned long parent_rate,
+		 unsigned int *pm, unsigned int *pn, unsigned int *pod)
+{
+	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+	unsigned int m, n, od;
+
+	if (pll_info->calc_m_n_od)
+		(*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od);
+	else
+		ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od);
 
 	if (pm)
 		*pm = m;
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 10521d1b7b12..bfc2b9c38a41 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -55,6 +55,9 @@ struct ingenic_cgu_pll_info {
 	s8 bypass_bit;
 	u8 enable_bit;
 	u8 stable_bit;
+	void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
+			    unsigned long rate, unsigned long parent_rate,
+			    unsigned int *m, unsigned int *n, unsigned int *od);
 };
 
 /**
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/6] clk: ingenic: Add support for the JZ4760
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (4 preceding siblings ...)
  2021-03-07 14:17 ` [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm Paul Cercueil
@ 2021-03-07 14:17 ` Paul Cercueil
  2021-03-17 12:41   ` Zhou Yanjie
  2021-03-09  6:31 ` [PATCH 0/6] clk: Ingenic JZ4760(B) support Zhou Yanjie
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Paul Cercueil @ 2021-03-07 14:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Zhou Yanjie
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips, Paul Cercueil

Add the CGU code and the compatible string to the TCU driver to support
the JZ4760 SoC.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clk/ingenic/Kconfig            |  10 +
 drivers/clk/ingenic/Makefile           |   1 +
 drivers/clk/ingenic/jz4760-cgu.c       | 433 +++++++++++++++++++++++++
 drivers/clk/ingenic/tcu.c              |   2 +
 include/dt-bindings/clock/jz4760-cgu.h |  54 +++
 5 files changed, 500 insertions(+)
 create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
 create mode 100644 include/dt-bindings/clock/jz4760-cgu.h

diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
index 580b0cf69ed5..898f1bc478c9 100644
--- a/drivers/clk/ingenic/Kconfig
+++ b/drivers/clk/ingenic/Kconfig
@@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
 
 	  If building for a JZ4725B SoC, you want to say Y here.
 
+config INGENIC_CGU_JZ4760
+	bool "Ingenic JZ4760 CGU driver"
+	default MACH_JZ4760
+	select INGENIC_CGU_COMMON
+	help
+	  Support the clocks provided by the CGU hardware on Ingenic JZ4760
+	  and compatible SoCs.
+
+	  If building for a JZ4760 SoC, you want to say Y here.
+
 config INGENIC_CGU_JZ4770
 	bool "Ingenic JZ4770 CGU driver"
 	default MACH_JZ4770
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index aaa4bffe03c6..9edfaf4610b9 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_INGENIC_CGU_COMMON)	+= cgu.o pm.o
 obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4725B)	+= jz4725b-cgu.o
+obj-$(CONFIG_INGENIC_CGU_JZ4760)	+= jz4760-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4770)	+= jz4770-cgu.o
 obj-$(CONFIG_INGENIC_CGU_JZ4780)	+= jz4780-cgu.o
 obj-$(CONFIG_INGENIC_CGU_X1000)		+= x1000-cgu.o
diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c
new file mode 100644
index 000000000000..a45327cba7d1
--- /dev/null
+++ b/drivers/clk/ingenic/jz4760-cgu.c
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4760 SoC CGU driver
+ * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/jz4760-cgu.h>
+
+#include "cgu.h"
+#include "pm.h"
+
+#define MHZ (1000 * 1000)
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR		0x00
+#define CGU_REG_LCR		0x04
+#define CGU_REG_CPPCR0		0x10
+#define CGU_REG_CLKGR0		0x20
+#define CGU_REG_OPCR		0x24
+#define CGU_REG_CLKGR1		0x28
+#define CGU_REG_CPPCR1		0x30
+#define CGU_REG_USBPCR		0x3c
+#define CGU_REG_USBCDR		0x50
+#define CGU_REG_I2SCDR		0x60
+#define CGU_REG_LPCDR		0x64
+#define CGU_REG_MSCCDR		0x68
+#define CGU_REG_UHCCDR		0x6c
+#define CGU_REG_SSICDR		0x74
+#define CGU_REG_CIMCDR		0x7c
+#define CGU_REG_GPSCDR		0x80
+#define CGU_REG_PCMCDR		0x84
+#define CGU_REG_GPUCDR		0x88
+
+static const s8 pll_od_encoding[8] = {
+	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const u8 jz4760_cgu_cpccr_div_table[] = {
+	1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4760_cgu_pll_half_div_table[] = {
+	2, 1,
+};
+
+static void
+jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
+		       unsigned long rate, unsigned long parent_rate,
+		       unsigned int *pm, unsigned int *pn, unsigned int *pod)
+{
+	unsigned int m, n, od;
+
+	/* The output of the PLL must be between 500 and 1500 MHz. */
+	rate = clamp_val(rate, 500ul * MHZ, 1500ul * MHZ);
+
+	/* The frequency after the N divider must be between 1 and 50 MHz. */
+	n = parent_rate / (1 * MHZ);
+
+	/* The N divider must be >= 2. */
+	n = clamp_val(n, 2, 1 << pll_info->n_bits);
+
+	for (;;) {
+		od = 0;
+
+		do {
+			m = (rate / MHZ) * ++od * n / (parent_rate / MHZ);
+		} while (m < pll_info->m_offset || m & 1);
+
+		if (m <= (1 << pll_info->m_bits) - 2)
+			break;
+
+		n >>= 1;
+	}
+
+	*pm = m;
+	*pn = n;
+	*pod = od;
+}
+
+static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
+
+	/* External clocks */
+
+	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
+	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+	/* PLLs */
+
+	[JZ4760_CLK_PLL0] = {
+		"pll0", CGU_CLK_PLL,
+		.parents = { JZ4760_CLK_EXT },
+		.pll = {
+			.reg = CGU_REG_CPPCR0,
+			.rate_multiplier = 1,
+			.m_shift = 23,
+			.m_bits = 8,
+			.m_offset = 0,
+			.n_shift = 18,
+			.n_bits = 4,
+			.n_offset = 0,
+			.od_shift = 16,
+			.od_bits = 2,
+			.od_max = 8,
+			.od_encoding = pll_od_encoding,
+			.bypass_reg = CGU_REG_CPPCR0,
+			.bypass_bit = 9,
+			.enable_bit = 8,
+			.stable_bit = 10,
+			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
+		},
+	},
+
+	[JZ4760_CLK_PLL1] = {
+		/* TODO: PLL1 can depend on PLL0 */
+		"pll1", CGU_CLK_PLL,
+		.parents = { JZ4760_CLK_EXT },
+		.pll = {
+			.reg = CGU_REG_CPPCR1,
+			.rate_multiplier = 1,
+			.m_shift = 23,
+			.m_bits = 8,
+			.m_offset = 0,
+			.n_shift = 18,
+			.n_bits = 4,
+			.n_offset = 0,
+			.od_shift = 16,
+			.od_bits = 2,
+			.od_max = 8,
+			.od_encoding = pll_od_encoding,
+			.bypass_bit = -1,
+			.enable_bit = 7,
+			.stable_bit = 6,
+			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
+		},
+	},
+
+	/* Main clocks */
+
+	[JZ4760_CLK_CCLK] = {
+		"cclk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+	[JZ4760_CLK_HCLK] = {
+		"hclk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+	[JZ4760_CLK_SCLK] = {
+		"sclk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+	[JZ4760_CLK_H2CLK] = {
+		"h2clk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+	[JZ4760_CLK_MCLK] = {
+		"mclk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+	[JZ4760_CLK_PCLK] = {
+		"pclk", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0, },
+		.div = {
+			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
+			jz4760_cgu_cpccr_div_table,
+		},
+	},
+
+	/* Divided clocks */
+
+	[JZ4760_CLK_PLL0_HALF] = {
+		"pll0_half", CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_PLL0 },
+		.div = {
+			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
+			jz4760_cgu_pll_half_div_table,
+		},
+	},
+
+	/* Those divided clocks can connect to PLL0 or PLL1 */
+
+	[JZ4760_CLK_UHC] = {
+		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+		.mux = { CGU_REG_UHCCDR, 31, 1 },
+		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR0, 24 },
+	},
+	[JZ4760_CLK_GPU] = {
+		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+		.mux = { CGU_REG_GPUCDR, 31, 1 },
+		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR1, 9 },
+	},
+	[JZ4760_CLK_LPCLK_DIV] = {
+		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+		.mux = { CGU_REG_LPCDR, 29, 1 },
+		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+	},
+	[JZ4760_CLK_TVE] = {
+		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
+		.mux = { CGU_REG_LPCDR, 31, 1 },
+		.gate = { CGU_REG_CLKGR0, 27 },
+	},
+	[JZ4760_CLK_LPCLK] = {
+		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
+		.mux = { CGU_REG_LPCDR, 30, 1 },
+		.gate = { CGU_REG_CLKGR0, 28 },
+	},
+	[JZ4760_CLK_GPS] = {
+		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+		.mux = { CGU_REG_GPSCDR, 31, 1 },
+		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR0, 22 },
+	},
+
+	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+	[JZ4760_CLK_PCM] = {
+		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_EXT, -1,
+			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+		.mux = { CGU_REG_PCMCDR, 30, 2 },
+		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
+		.gate = { CGU_REG_CLKGR1, 8 },
+	},
+	[JZ4760_CLK_I2S] = {
+		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_EXT, -1,
+			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+		.mux = { CGU_REG_I2SCDR, 30, 2 },
+		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
+	},
+	[JZ4760_CLK_OTG] = {
+		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_EXT, -1,
+			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+		.mux = { CGU_REG_USBCDR, 30, 2 },
+		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR0, 2 },
+	},
+
+	/* Those divided clocks can connect to EXT or PLL0 */
+	[JZ4760_CLK_MMC_MUX] = {
+		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
+		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
+		.mux = { CGU_REG_MSCCDR, 31, 1 },
+		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
+	},
+	[JZ4760_CLK_SSI_MUX] = {
+		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
+		.mux = { CGU_REG_SSICDR, 31, 1 },
+		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
+	},
+
+	/* These divided clock can connect to PLL0 only */
+	[JZ4760_CLK_CIM] = {
+		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_PLL0_HALF },
+		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+		.gate = { CGU_REG_CLKGR0, 26 },
+	},
+
+	/* Gate-only clocks */
+
+	[JZ4760_CLK_SSI0] = {
+		"ssi0", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_SSI_MUX, },
+		.gate = { CGU_REG_CLKGR0, 4 },
+	},
+	[JZ4760_CLK_SSI1] = {
+		"ssi1", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_SSI_MUX, },
+		.gate = { CGU_REG_CLKGR0, 19 },
+	},
+	[JZ4760_CLK_SSI2] = {
+		"ssi2", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_SSI_MUX, },
+		.gate = { CGU_REG_CLKGR0, 20 },
+	},
+	[JZ4760_CLK_DMA] = {
+		"dma", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_H2CLK, },
+		.gate = { CGU_REG_CLKGR0, 21 },
+	},
+	[JZ4760_CLK_I2C0] = {
+		"i2c0", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 5 },
+	},
+	[JZ4760_CLK_I2C1] = {
+		"i2c1", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 6 },
+	},
+	[JZ4760_CLK_UART0] = {
+		"uart0", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 15 },
+	},
+	[JZ4760_CLK_UART1] = {
+		"uart1", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 16 },
+	},
+	[JZ4760_CLK_UART2] = {
+		"uart2", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 17 },
+	},
+	[JZ4760_CLK_UART3] = {
+		"uart3", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 18 },
+	},
+	[JZ4760_CLK_IPU] = {
+		"ipu", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_HCLK, },
+		.gate = { CGU_REG_CLKGR0, 29 },
+	},
+	[JZ4760_CLK_ADC] = {
+		"adc", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 14 },
+	},
+	[JZ4760_CLK_AIC] = {
+		"aic", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_EXT, },
+		.gate = { CGU_REG_CLKGR0, 8 },
+	},
+	[JZ4760_CLK_VPU] = {
+		"vpu", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_HCLK, },
+		.gate = { CGU_REG_LCR, 30, false, 150 },
+	},
+	[JZ4760_CLK_MMC0] = {
+		"mmc0", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_MMC_MUX, },
+		.gate = { CGU_REG_CLKGR0, 3 },
+	},
+	[JZ4760_CLK_MMC1] = {
+		"mmc1", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_MMC_MUX, },
+		.gate = { CGU_REG_CLKGR0, 11 },
+	},
+	[JZ4760_CLK_MMC2] = {
+		"mmc2", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_MMC_MUX, },
+		.gate = { CGU_REG_CLKGR0, 12 },
+	},
+	[JZ4760_CLK_UHC_PHY] = {
+		"uhc_phy", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_UHC, },
+		.gate = { CGU_REG_OPCR, 5 },
+	},
+	[JZ4760_CLK_OTG_PHY] = {
+		"usb_phy", CGU_CLK_GATE,
+		.parents = { JZ4760_CLK_OTG },
+		.gate = { CGU_REG_OPCR, 7, true, 50 },
+	},
+
+	/* Custom clocks */
+	[JZ4760_CLK_EXT512] = {
+		"ext/512", CGU_CLK_FIXDIV,
+		.parents = { JZ4760_CLK_EXT },
+		.fixdiv = { 512 },
+	},
+	[JZ4760_CLK_RTC] = {
+		"rtc", CGU_CLK_MUX,
+		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
+		.mux = { CGU_REG_OPCR, 2, 1},
+	},
+};
+
+static void __init jz4760_cgu_init(struct device_node *np)
+{
+	struct ingenic_cgu *cgu;
+	int retval;
+
+	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
+			      ARRAY_SIZE(jz4760_cgu_clocks), np);
+	if (!cgu) {
+		pr_err("%s: failed to initialise CGU\n", __func__);
+		return;
+	}
+
+	retval = ingenic_cgu_register_clocks(cgu);
+	if (retval)
+		pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+	ingenic_cgu_register_syscore_ops(cgu);
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
+
+/* JZ4760B has some small differences, but we don't implement them. */
+CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
index 9382dc3aa27e..77acfbeb4830 100644
--- a/drivers/clk/ingenic/tcu.c
+++ b/drivers/clk/ingenic/tcu.c
@@ -326,6 +326,7 @@ static const struct ingenic_soc_info x1000_soc_info = {
 static const struct of_device_id __maybe_unused ingenic_tcu_of_match[] __initconst = {
 	{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
 	{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
+	{ .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, },
 	{ .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, },
 	{ .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
 	{ /* sentinel */ }
@@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct device_node *np)
 
 CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init);
 CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init);
+CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", ingenic_tcu_init);
 CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init);
 CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init);
diff --git a/include/dt-bindings/clock/jz4760-cgu.h b/include/dt-bindings/clock/jz4760-cgu.h
new file mode 100644
index 000000000000..4bb2e19c4743
--- /dev/null
+++ b/include/dt-bindings/clock/jz4760-cgu.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides clock numbers for the ingenic,jz4760-cgu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
+
+#define JZ4760_CLK_EXT		0
+#define JZ4760_CLK_OSC32K	1
+#define JZ4760_CLK_PLL0		2
+#define JZ4760_CLK_PLL0_HALF	3
+#define JZ4760_CLK_PLL1		4
+#define JZ4760_CLK_CCLK		5
+#define JZ4760_CLK_HCLK		6
+#define JZ4760_CLK_SCLK		7
+#define JZ4760_CLK_H2CLK	8
+#define JZ4760_CLK_MCLK		9
+#define JZ4760_CLK_PCLK		10
+#define JZ4760_CLK_MMC_MUX	11
+#define JZ4760_CLK_MMC0		12
+#define JZ4760_CLK_MMC1		13
+#define JZ4760_CLK_MMC2		14
+#define JZ4760_CLK_CIM		15
+#define JZ4760_CLK_UHC		16
+#define JZ4760_CLK_GPU		17
+#define JZ4760_CLK_GPS		18
+#define JZ4760_CLK_SSI_MUX	19
+#define JZ4760_CLK_PCM		20
+#define JZ4760_CLK_I2S		21
+#define JZ4760_CLK_OTG		22
+#define JZ4760_CLK_SSI0		23
+#define JZ4760_CLK_SSI1		24
+#define JZ4760_CLK_SSI2		25
+#define JZ4760_CLK_DMA		26
+#define JZ4760_CLK_I2C0		27
+#define JZ4760_CLK_I2C1		28
+#define JZ4760_CLK_UART0	29
+#define JZ4760_CLK_UART1	30
+#define JZ4760_CLK_UART2	31
+#define JZ4760_CLK_UART3	32
+#define JZ4760_CLK_IPU		33
+#define JZ4760_CLK_ADC		34
+#define JZ4760_CLK_AIC		35
+#define JZ4760_CLK_VPU		36
+#define JZ4760_CLK_UHC_PHY	37
+#define JZ4760_CLK_OTG_PHY	38
+#define JZ4760_CLK_EXT512	39
+#define JZ4760_CLK_RTC		40
+#define JZ4760_CLK_LPCLK_DIV	41
+#define JZ4760_CLK_TVE		42
+#define JZ4760_CLK_LPCLK	43
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4760_CGU_H__ */
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
  2021-03-07 14:17 ` [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles Paul Cercueil
@ 2021-03-08 22:56   ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2021-03-08 22:56 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Stephen Boyd, od, linux-clk, devicetree, linux-mips, Rob Herring,
	Michael Turquette, Zhou Yanjie, linux-kernel

On Sun, 07 Mar 2021 14:17:54 +0000, Paul Cercueil wrote:
> Add ingenic,jz4760-cgu and ingenic,jz4760b-cgu compatible strings for
> the JZ4760 and JZ4760B SoCs respectively.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  Documentation/devicetree/bindings/clock/ingenic,cgu.yaml | 4 ++++
>  1 file changed, 4 insertions(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] clk: Ingenic JZ4760(B) support
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (5 preceding siblings ...)
  2021-03-07 14:17 ` [PATCH 6/6] clk: ingenic: Add support for the JZ4760 Paul Cercueil
@ 2021-03-09  6:31 ` Zhou Yanjie
  2021-03-09 15:33 ` Zhou Yanjie
  2021-03-10 14:40 ` Zhou Yanjie
  8 siblings, 0 replies; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-09  6:31 UTC (permalink / raw)
  To: Paul Cercueil, Michael Turquette, Stephen Boyd, Rob Herring
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/7 下午10:17, Paul Cercueil wrote:
> Hi,
>
> Here are a set of patches to add support for the Ingenic JZ4760(B) SoCs.
>
> One thing to note is that the ingenic,jz4760-tcu is undocumented for now,
> as I will update the TCU documentation in a different patchset.
>
> Zhou: the CGU code now supports overriding the PLL M/N/OD calc
> algorithm, please tell me if it works for you.


After set "od = 1;", the overriding works, but I think we still need 
some further improvements related to OD,

because there is no OD bits in the I2S PLL, this will cause error in 
"ingenic_pll_recalc_rate()", and may cause

"ingenic_pll_calc()" to also have error(if we will introduce support for 
non 1 od values).


I think maybe we can add codes to detect if there is an 
"pll_od_encoding". If it is NULL, it means no OD bits, then

do some corresponding processing( for example, setting corresponding 
variable to 1) to ensure proper calculation.


Thanks and best regards!


> Cheers,
> -Paul
>
> Paul Cercueil (6):
>    dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
>    clk: Support bypassing dividers
>    clk: ingenic: Read bypass register only when there is one
>    clk: ingenic: Remove pll_info.no_bypass_bit
>    clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
>    clk: ingenic: Add support for the JZ4760
>
>   .../bindings/clock/ingenic,cgu.yaml           |   4 +
>   drivers/clk/ingenic/Kconfig                   |  10 +
>   drivers/clk/ingenic/Makefile                  |   1 +
>   drivers/clk/ingenic/cgu.c                     |  92 ++--
>   drivers/clk/ingenic/cgu.h                     |  12 +-
>   drivers/clk/ingenic/jz4725b-cgu.c             |  12 +-
>   drivers/clk/ingenic/jz4740-cgu.c              |  12 +-
>   drivers/clk/ingenic/jz4760-cgu.c              | 433 ++++++++++++++++++
>   drivers/clk/ingenic/jz4770-cgu.c              |  15 +-
>   drivers/clk/ingenic/tcu.c                     |   2 +
>   include/dt-bindings/clock/jz4760-cgu.h        |  54 +++
>   11 files changed, 591 insertions(+), 56 deletions(-)
>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] clk: Ingenic JZ4760(B) support
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (6 preceding siblings ...)
  2021-03-09  6:31 ` [PATCH 0/6] clk: Ingenic JZ4760(B) support Zhou Yanjie
@ 2021-03-09 15:33 ` Zhou Yanjie
  2021-03-10 14:40 ` Zhou Yanjie
  8 siblings, 0 replies; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-09 15:33 UTC (permalink / raw)
  To: Paul Cercueil, Michael Turquette, Stephen Boyd, Rob Herring
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/7 下午10:17, Paul Cercueil wrote:
> Hi,
>
> Here are a set of patches to add support for the Ingenic JZ4760(B) SoCs.
>
> One thing to note is that the ingenic,jz4760-tcu is undocumented for now,
> as I will update the TCU documentation in a different patchset.
>
> Zhou: the CGU code now supports overriding the PLL M/N/OD calc
> algorithm, please tell me if it works for you.


Newly found two problems, the first problem is because I2S PLL does not 
have a stable bit, so we need to follow the bypass bit, which is only do 
corresponding processing when "stable_bit > = 0".

The second problem is that the I2S PLL cannot switch the parent clock 
after using the PLL framework, so it cannot use SCLKA and MPLL as the 
parent clock (when trying to switch the parent clock, it will stuck and 
accompany "clk: failed  to reparent i2s to mpll: -22").


>
> Cheers,
> -Paul
>
> Paul Cercueil (6):
>    dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
>    clk: Support bypassing dividers
>    clk: ingenic: Read bypass register only when there is one
>    clk: ingenic: Remove pll_info.no_bypass_bit
>    clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
>    clk: ingenic: Add support for the JZ4760
>
>   .../bindings/clock/ingenic,cgu.yaml           |   4 +
>   drivers/clk/ingenic/Kconfig                   |  10 +
>   drivers/clk/ingenic/Makefile                  |   1 +
>   drivers/clk/ingenic/cgu.c                     |  92 ++--
>   drivers/clk/ingenic/cgu.h                     |  12 +-
>   drivers/clk/ingenic/jz4725b-cgu.c             |  12 +-
>   drivers/clk/ingenic/jz4740-cgu.c              |  12 +-
>   drivers/clk/ingenic/jz4760-cgu.c              | 433 ++++++++++++++++++
>   drivers/clk/ingenic/jz4770-cgu.c              |  15 +-
>   drivers/clk/ingenic/tcu.c                     |   2 +
>   include/dt-bindings/clock/jz4760-cgu.h        |  54 +++
>   11 files changed, 591 insertions(+), 56 deletions(-)
>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] clk: Ingenic JZ4760(B) support
  2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
                   ` (7 preceding siblings ...)
  2021-03-09 15:33 ` Zhou Yanjie
@ 2021-03-10 14:40 ` Zhou Yanjie
  8 siblings, 0 replies; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-10 14:40 UTC (permalink / raw)
  To: Paul Cercueil, Michael Turquette, Stephen Boyd, Rob Herring
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/7 下午10:17, Paul Cercueil wrote:
> Hi,
>
> Here are a set of patches to add support for the Ingenic JZ4760(B) SoCs.
>
> One thing to note is that the ingenic,jz4760-tcu is undocumented for now,
> as I will update the TCU documentation in a different patchset.
>
> Zhou: the CGU code now supports overriding the PLL M/N/OD calc
> algorithm, please tell me if it works for you.


The previously mentioned problems have all been solved, this proves that 
your patch is available for I2S PLL.

I will improve and clean up the relevant code, then send it immediately 
after your patches is merged.


Thanks and best regards!


> Cheers,
> -Paul
>
> Paul Cercueil (6):
>    dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles
>    clk: Support bypassing dividers
>    clk: ingenic: Read bypass register only when there is one
>    clk: ingenic: Remove pll_info.no_bypass_bit
>    clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
>    clk: ingenic: Add support for the JZ4760
>
>   .../bindings/clock/ingenic,cgu.yaml           |   4 +
>   drivers/clk/ingenic/Kconfig                   |  10 +
>   drivers/clk/ingenic/Makefile                  |   1 +
>   drivers/clk/ingenic/cgu.c                     |  92 ++--
>   drivers/clk/ingenic/cgu.h                     |  12 +-
>   drivers/clk/ingenic/jz4725b-cgu.c             |  12 +-
>   drivers/clk/ingenic/jz4740-cgu.c              |  12 +-
>   drivers/clk/ingenic/jz4760-cgu.c              | 433 ++++++++++++++++++
>   drivers/clk/ingenic/jz4770-cgu.c              |  15 +-
>   drivers/clk/ingenic/tcu.c                     |   2 +
>   include/dt-bindings/clock/jz4760-cgu.h        |  54 +++
>   11 files changed, 591 insertions(+), 56 deletions(-)
>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm
  2021-03-07 14:17 ` [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm Paul Cercueil
@ 2021-03-10 14:42   ` Zhou Yanjie
  0 siblings, 0 replies; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-10 14:42 UTC (permalink / raw)
  To: Paul Cercueil, Michael Turquette, Stephen Boyd, Rob Herring
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/7 下午10:17, Paul Cercueil wrote:
> SoC-specific code can now provide a callback if they need to compute the
> M/N/OD values in a specific way.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>   drivers/clk/ingenic/cgu.c | 40 ++++++++++++++++++++++++++-------------
>   drivers/clk/ingenic/cgu.h |  3 +++
>   2 files changed, 30 insertions(+), 13 deletions(-)


Tested-by: 周琰杰 (Zhou Yanjie)<zhouyanjie@wanyeetech.com>   # on CU1000-neo/X1000E


> diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
> index 58f7ab5cf0fe..266c7595d330 100644
> --- a/drivers/clk/ingenic/cgu.c
> +++ b/drivers/clk/ingenic/cgu.c
> @@ -119,28 +119,42 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
>   		n * od);
>   }
>   
> -static unsigned long
> -ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
> -		 unsigned long rate, unsigned long parent_rate,
> -		 unsigned *pm, unsigned *pn, unsigned *pod)
> +static void
> +ingenic_pll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
> +			unsigned long rate, unsigned long parent_rate,
> +			unsigned int *pm, unsigned int *pn, unsigned int *pod)
>   {
> -	const struct ingenic_cgu_pll_info *pll_info;
> -	unsigned m, n, od;
> -
> -	pll_info = &clk_info->pll;
> -	od = 1;
> +	unsigned int m, n, od = 1;
>   
>   	/*
>   	 * The frequency after the input divider must be between 10 and 50 MHz.
>   	 * The highest divider yields the best resolution.
>   	 */
>   	n = parent_rate / (10 * MHZ);
> -	n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
> -	n = max_t(unsigned, n, pll_info->n_offset);
> +	n = min_t(unsigned int, n, 1 << pll_info->n_bits);
> +	n = max_t(unsigned int, n, pll_info->n_offset);
>   
>   	m = (rate / MHZ) * od * n / (parent_rate / MHZ);
> -	m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
> -	m = max_t(unsigned, m, pll_info->m_offset);
> +	m = min_t(unsigned int, m, 1 << pll_info->m_bits);
> +	m = max_t(unsigned int, m, pll_info->m_offset);
> +
> +	*pm = m;
> +	*pn = n;
> +	*pod = od;
> +}
> +
> +static unsigned long
> +ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
> +		 unsigned long rate, unsigned long parent_rate,
> +		 unsigned int *pm, unsigned int *pn, unsigned int *pod)
> +{
> +	const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
> +	unsigned int m, n, od;
> +
> +	if (pll_info->calc_m_n_od)
> +		(*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od);
> +	else
> +		ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od);
>   
>   	if (pm)
>   		*pm = m;
> diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
> index 10521d1b7b12..bfc2b9c38a41 100644
> --- a/drivers/clk/ingenic/cgu.h
> +++ b/drivers/clk/ingenic/cgu.h
> @@ -55,6 +55,9 @@ struct ingenic_cgu_pll_info {
>   	s8 bypass_bit;
>   	u8 enable_bit;
>   	u8 stable_bit;
> +	void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
> +			    unsigned long rate, unsigned long parent_rate,
> +			    unsigned int *m, unsigned int *n, unsigned int *od);
>   };
>   
>   /**

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 6/6] clk: ingenic: Add support for the JZ4760
  2021-03-07 14:17 ` [PATCH 6/6] clk: ingenic: Add support for the JZ4760 Paul Cercueil
@ 2021-03-17 12:41   ` Zhou Yanjie
  2021-03-22 17:40     ` Paul Cercueil
  0 siblings, 1 reply; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-17 12:41 UTC (permalink / raw)
  To: Paul Cercueil, Michael Turquette, Stephen Boyd, Rob Herring
  Cc: od, linux-clk, devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/7 下午10:17, Paul Cercueil wrote:
> Add the CGU code and the compatible string to the TCU driver to support
> the JZ4760 SoC.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>   drivers/clk/ingenic/Kconfig            |  10 +
>   drivers/clk/ingenic/Makefile           |   1 +
>   drivers/clk/ingenic/jz4760-cgu.c       | 433 +++++++++++++++++++++++++
>   drivers/clk/ingenic/tcu.c              |   2 +
>   include/dt-bindings/clock/jz4760-cgu.h |  54 +++
>   5 files changed, 500 insertions(+)
>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>
> diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
> index 580b0cf69ed5..898f1bc478c9 100644
> --- a/drivers/clk/ingenic/Kconfig
> +++ b/drivers/clk/ingenic/Kconfig
> @@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
>   
>   	  If building for a JZ4725B SoC, you want to say Y here.
>   
> +config INGENIC_CGU_JZ4760
> +	bool "Ingenic JZ4760 CGU driver"
> +	default MACH_JZ4760
> +	select INGENIC_CGU_COMMON
> +	help
> +	  Support the clocks provided by the CGU hardware on Ingenic JZ4760
> +	  and compatible SoCs.
> +
> +	  If building for a JZ4760 SoC, you want to say Y here.
> +
>   config INGENIC_CGU_JZ4770
>   	bool "Ingenic JZ4770 CGU driver"
>   	default MACH_JZ4770
> diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
> index aaa4bffe03c6..9edfaf4610b9 100644
> --- a/drivers/clk/ingenic/Makefile
> +++ b/drivers/clk/ingenic/Makefile
> @@ -2,6 +2,7 @@
>   obj-$(CONFIG_INGENIC_CGU_COMMON)	+= cgu.o pm.o
>   obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
>   obj-$(CONFIG_INGENIC_CGU_JZ4725B)	+= jz4725b-cgu.o
> +obj-$(CONFIG_INGENIC_CGU_JZ4760)	+= jz4760-cgu.o
>   obj-$(CONFIG_INGENIC_CGU_JZ4770)	+= jz4770-cgu.o
>   obj-$(CONFIG_INGENIC_CGU_JZ4780)	+= jz4780-cgu.o
>   obj-$(CONFIG_INGENIC_CGU_X1000)		+= x1000-cgu.o
> diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c
> new file mode 100644
> index 000000000000..a45327cba7d1
> --- /dev/null
> +++ b/drivers/clk/ingenic/jz4760-cgu.c
> @@ -0,0 +1,433 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * JZ4760 SoC CGU driver
> + * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +
> +#include <linux/clk.h>
> +
> +#include <dt-bindings/clock/jz4760-cgu.h>
> +
> +#include "cgu.h"
> +#include "pm.h"
> +
> +#define MHZ (1000 * 1000)
> +
> +/*
> + * CPM registers offset address definition
> + */
> +#define CGU_REG_CPCCR		0x00
> +#define CGU_REG_LCR		0x04
> +#define CGU_REG_CPPCR0		0x10
> +#define CGU_REG_CLKGR0		0x20
> +#define CGU_REG_OPCR		0x24
> +#define CGU_REG_CLKGR1		0x28
> +#define CGU_REG_CPPCR1		0x30
> +#define CGU_REG_USBPCR		0x3c
> +#define CGU_REG_USBCDR		0x50
> +#define CGU_REG_I2SCDR		0x60
> +#define CGU_REG_LPCDR		0x64
> +#define CGU_REG_MSCCDR		0x68
> +#define CGU_REG_UHCCDR		0x6c
> +#define CGU_REG_SSICDR		0x74
> +#define CGU_REG_CIMCDR		0x7c
> +#define CGU_REG_GPSCDR		0x80
> +#define CGU_REG_PCMCDR		0x84
> +#define CGU_REG_GPUCDR		0x88
> +
> +static const s8 pll_od_encoding[8] = {
> +	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
> +};
> +
> +static const u8 jz4760_cgu_cpccr_div_table[] = {
> +	1, 2, 3, 4, 6, 8,
> +};
> +
> +static const u8 jz4760_cgu_pll_half_div_table[] = {
> +	2, 1,
> +};
> +
> +static void
> +jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
> +		       unsigned long rate, unsigned long parent_rate,
> +		       unsigned int *pm, unsigned int *pn, unsigned int *pod)
> +{
> +	unsigned int m, n, od;
> +
> +	/* The output of the PLL must be between 500 and 1500 MHz. */
> +	rate = clamp_val(rate, 500ul * MHZ, 1500ul * MHZ);
> +
> +	/* The frequency after the N divider must be between 1 and 50 MHz. */
> +	n = parent_rate / (1 * MHZ);
> +
> +	/* The N divider must be >= 2. */
> +	n = clamp_val(n, 2, 1 << pll_info->n_bits);
> +
> +	for (;;) {
> +		od = 0;
> +
> +		do {
> +			m = (rate / MHZ) * ++od * n / (parent_rate / MHZ);


Please correct me if I am wrong, according to the PM, when the register 
value of OD is 0, 1, 2, 3, the value corresponding participating PL 
frequency calculation is 1, 2, 4, 8. Therefore, change

m = (rate / MHZ) * ++od * n / (parent_rate / MHZ); to m = (rate / MHZ) * (2 ^ od++) * n / (parent_rate / MHZ); seems to be more appropriate, it can avoid 3, 5, 6, and 7 that should not exist.


> +		} while (m < pll_info->m_offset || m & 1);
> +
> +		if (m <= (1 << pll_info->m_bits) - 2)
> +			break;
> +
> +		n >>= 1;
> +	}
> +
> +	*pm = m;
> +	*pn = n;
> +	*pod = od;


If we change the above formula, we also need to change this to *pod = 2 
^ od;


Thanks and best regards!


> +}
> +
> +static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
> +
> +	/* External clocks */
> +
> +	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
> +	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
> +
> +	/* PLLs */
> +
> +	[JZ4760_CLK_PLL0] = {
> +		"pll0", CGU_CLK_PLL,
> +		.parents = { JZ4760_CLK_EXT },
> +		.pll = {
> +			.reg = CGU_REG_CPPCR0,
> +			.rate_multiplier = 1,
> +			.m_shift = 23,
> +			.m_bits = 8,
> +			.m_offset = 0,
> +			.n_shift = 18,
> +			.n_bits = 4,
> +			.n_offset = 0,
> +			.od_shift = 16,
> +			.od_bits = 2,
> +			.od_max = 8,
> +			.od_encoding = pll_od_encoding,
> +			.bypass_reg = CGU_REG_CPPCR0,
> +			.bypass_bit = 9,
> +			.enable_bit = 8,
> +			.stable_bit = 10,
> +			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
> +		},
> +	},
> +
> +	[JZ4760_CLK_PLL1] = {
> +		/* TODO: PLL1 can depend on PLL0 */
> +		"pll1", CGU_CLK_PLL,
> +		.parents = { JZ4760_CLK_EXT },
> +		.pll = {
> +			.reg = CGU_REG_CPPCR1,
> +			.rate_multiplier = 1,
> +			.m_shift = 23,
> +			.m_bits = 8,
> +			.m_offset = 0,
> +			.n_shift = 18,
> +			.n_bits = 4,
> +			.n_offset = 0,
> +			.od_shift = 16,
> +			.od_bits = 2,
> +			.od_max = 8,
> +			.od_encoding = pll_od_encoding,
> +			.bypass_bit = -1,
> +			.enable_bit = 7,
> +			.stable_bit = 6,
> +			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
> +		},
> +	},
> +
> +	/* Main clocks */
> +
> +	[JZ4760_CLK_CCLK] = {
> +		"cclk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +	[JZ4760_CLK_HCLK] = {
> +		"hclk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +	[JZ4760_CLK_SCLK] = {
> +		"sclk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +	[JZ4760_CLK_H2CLK] = {
> +		"h2clk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +	[JZ4760_CLK_MCLK] = {
> +		"mclk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +	[JZ4760_CLK_PCLK] = {
> +		"pclk", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0, },
> +		.div = {
> +			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
> +			jz4760_cgu_cpccr_div_table,
> +		},
> +	},
> +
> +	/* Divided clocks */
> +
> +	[JZ4760_CLK_PLL0_HALF] = {
> +		"pll0_half", CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_PLL0 },
> +		.div = {
> +			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
> +			jz4760_cgu_pll_half_div_table,
> +		},
> +	},
> +
> +	/* Those divided clocks can connect to PLL0 or PLL1 */
> +
> +	[JZ4760_CLK_UHC] = {
> +		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
> +		.mux = { CGU_REG_UHCCDR, 31, 1 },
> +		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR0, 24 },
> +	},
> +	[JZ4760_CLK_GPU] = {
> +		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
> +		.mux = { CGU_REG_GPUCDR, 31, 1 },
> +		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR1, 9 },
> +	},
> +	[JZ4760_CLK_LPCLK_DIV] = {
> +		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
> +		.mux = { CGU_REG_LPCDR, 29, 1 },
> +		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
> +	},
> +	[JZ4760_CLK_TVE] = {
> +		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
> +		.mux = { CGU_REG_LPCDR, 31, 1 },
> +		.gate = { CGU_REG_CLKGR0, 27 },
> +	},
> +	[JZ4760_CLK_LPCLK] = {
> +		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
> +		.mux = { CGU_REG_LPCDR, 30, 1 },
> +		.gate = { CGU_REG_CLKGR0, 28 },
> +	},
> +	[JZ4760_CLK_GPS] = {
> +		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
> +		.mux = { CGU_REG_GPSCDR, 31, 1 },
> +		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR0, 22 },
> +	},
> +
> +	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
> +
> +	[JZ4760_CLK_PCM] = {
> +		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_EXT, -1,
> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
> +		.mux = { CGU_REG_PCMCDR, 30, 2 },
> +		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
> +		.gate = { CGU_REG_CLKGR1, 8 },
> +	},
> +	[JZ4760_CLK_I2S] = {
> +		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_EXT, -1,
> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
> +		.mux = { CGU_REG_I2SCDR, 30, 2 },
> +		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
> +	},
> +	[JZ4760_CLK_OTG] = {
> +		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_EXT, -1,
> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
> +		.mux = { CGU_REG_USBCDR, 30, 2 },
> +		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR0, 2 },
> +	},
> +
> +	/* Those divided clocks can connect to EXT or PLL0 */
> +	[JZ4760_CLK_MMC_MUX] = {
> +		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
> +		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
> +		.mux = { CGU_REG_MSCCDR, 31, 1 },
> +		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
> +	},
> +	[JZ4760_CLK_SSI_MUX] = {
> +		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
> +		.mux = { CGU_REG_SSICDR, 31, 1 },
> +		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
> +	},
> +
> +	/* These divided clock can connect to PLL0 only */
> +	[JZ4760_CLK_CIM] = {
> +		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_PLL0_HALF },
> +		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
> +		.gate = { CGU_REG_CLKGR0, 26 },
> +	},
> +
> +	/* Gate-only clocks */
> +
> +	[JZ4760_CLK_SSI0] = {
> +		"ssi0", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_SSI_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 4 },
> +	},
> +	[JZ4760_CLK_SSI1] = {
> +		"ssi1", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_SSI_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 19 },
> +	},
> +	[JZ4760_CLK_SSI2] = {
> +		"ssi2", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_SSI_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 20 },
> +	},
> +	[JZ4760_CLK_DMA] = {
> +		"dma", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_H2CLK, },
> +		.gate = { CGU_REG_CLKGR0, 21 },
> +	},
> +	[JZ4760_CLK_I2C0] = {
> +		"i2c0", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 5 },
> +	},
> +	[JZ4760_CLK_I2C1] = {
> +		"i2c1", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 6 },
> +	},
> +	[JZ4760_CLK_UART0] = {
> +		"uart0", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 15 },
> +	},
> +	[JZ4760_CLK_UART1] = {
> +		"uart1", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 16 },
> +	},
> +	[JZ4760_CLK_UART2] = {
> +		"uart2", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 17 },
> +	},
> +	[JZ4760_CLK_UART3] = {
> +		"uart3", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 18 },
> +	},
> +	[JZ4760_CLK_IPU] = {
> +		"ipu", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_HCLK, },
> +		.gate = { CGU_REG_CLKGR0, 29 },
> +	},
> +	[JZ4760_CLK_ADC] = {
> +		"adc", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 14 },
> +	},
> +	[JZ4760_CLK_AIC] = {
> +		"aic", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_EXT, },
> +		.gate = { CGU_REG_CLKGR0, 8 },
> +	},
> +	[JZ4760_CLK_VPU] = {
> +		"vpu", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_HCLK, },
> +		.gate = { CGU_REG_LCR, 30, false, 150 },
> +	},
> +	[JZ4760_CLK_MMC0] = {
> +		"mmc0", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_MMC_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 3 },
> +	},
> +	[JZ4760_CLK_MMC1] = {
> +		"mmc1", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_MMC_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 11 },
> +	},
> +	[JZ4760_CLK_MMC2] = {
> +		"mmc2", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_MMC_MUX, },
> +		.gate = { CGU_REG_CLKGR0, 12 },
> +	},
> +	[JZ4760_CLK_UHC_PHY] = {
> +		"uhc_phy", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_UHC, },
> +		.gate = { CGU_REG_OPCR, 5 },
> +	},
> +	[JZ4760_CLK_OTG_PHY] = {
> +		"usb_phy", CGU_CLK_GATE,
> +		.parents = { JZ4760_CLK_OTG },
> +		.gate = { CGU_REG_OPCR, 7, true, 50 },
> +	},
> +
> +	/* Custom clocks */
> +	[JZ4760_CLK_EXT512] = {
> +		"ext/512", CGU_CLK_FIXDIV,
> +		.parents = { JZ4760_CLK_EXT },
> +		.fixdiv = { 512 },
> +	},
> +	[JZ4760_CLK_RTC] = {
> +		"rtc", CGU_CLK_MUX,
> +		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
> +		.mux = { CGU_REG_OPCR, 2, 1},
> +	},
> +};
> +
> +static void __init jz4760_cgu_init(struct device_node *np)
> +{
> +	struct ingenic_cgu *cgu;
> +	int retval;
> +
> +	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
> +			      ARRAY_SIZE(jz4760_cgu_clocks), np);
> +	if (!cgu) {
> +		pr_err("%s: failed to initialise CGU\n", __func__);
> +		return;
> +	}
> +
> +	retval = ingenic_cgu_register_clocks(cgu);
> +	if (retval)
> +		pr_err("%s: failed to register CGU Clocks\n", __func__);
> +
> +	ingenic_cgu_register_syscore_ops(cgu);
> +}
> +
> +/* We only probe via devicetree, no need for a platform driver */
> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
> +
> +/* JZ4760B has some small differences, but we don't implement them. */
> +CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
> diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
> index 9382dc3aa27e..77acfbeb4830 100644
> --- a/drivers/clk/ingenic/tcu.c
> +++ b/drivers/clk/ingenic/tcu.c
> @@ -326,6 +326,7 @@ static const struct ingenic_soc_info x1000_soc_info = {
>   static const struct of_device_id __maybe_unused ingenic_tcu_of_match[] __initconst = {
>   	{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
>   	{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
> +	{ .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, },
>   	{ .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, },
>   	{ .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
>   	{ /* sentinel */ }
> @@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct device_node *np)
>   
>   CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init);
>   CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init);
> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", ingenic_tcu_init);
>   CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init);
>   CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init);
> diff --git a/include/dt-bindings/clock/jz4760-cgu.h b/include/dt-bindings/clock/jz4760-cgu.h
> new file mode 100644
> index 000000000000..4bb2e19c4743
> --- /dev/null
> +++ b/include/dt-bindings/clock/jz4760-cgu.h
> @@ -0,0 +1,54 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This header provides clock numbers for the ingenic,jz4760-cgu DT binding.
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
> +#define __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
> +
> +#define JZ4760_CLK_EXT		0
> +#define JZ4760_CLK_OSC32K	1
> +#define JZ4760_CLK_PLL0		2
> +#define JZ4760_CLK_PLL0_HALF	3
> +#define JZ4760_CLK_PLL1		4
> +#define JZ4760_CLK_CCLK		5
> +#define JZ4760_CLK_HCLK		6
> +#define JZ4760_CLK_SCLK		7
> +#define JZ4760_CLK_H2CLK	8
> +#define JZ4760_CLK_MCLK		9
> +#define JZ4760_CLK_PCLK		10
> +#define JZ4760_CLK_MMC_MUX	11
> +#define JZ4760_CLK_MMC0		12
> +#define JZ4760_CLK_MMC1		13
> +#define JZ4760_CLK_MMC2		14
> +#define JZ4760_CLK_CIM		15
> +#define JZ4760_CLK_UHC		16
> +#define JZ4760_CLK_GPU		17
> +#define JZ4760_CLK_GPS		18
> +#define JZ4760_CLK_SSI_MUX	19
> +#define JZ4760_CLK_PCM		20
> +#define JZ4760_CLK_I2S		21
> +#define JZ4760_CLK_OTG		22
> +#define JZ4760_CLK_SSI0		23
> +#define JZ4760_CLK_SSI1		24
> +#define JZ4760_CLK_SSI2		25
> +#define JZ4760_CLK_DMA		26
> +#define JZ4760_CLK_I2C0		27
> +#define JZ4760_CLK_I2C1		28
> +#define JZ4760_CLK_UART0	29
> +#define JZ4760_CLK_UART1	30
> +#define JZ4760_CLK_UART2	31
> +#define JZ4760_CLK_UART3	32
> +#define JZ4760_CLK_IPU		33
> +#define JZ4760_CLK_ADC		34
> +#define JZ4760_CLK_AIC		35
> +#define JZ4760_CLK_VPU		36
> +#define JZ4760_CLK_UHC_PHY	37
> +#define JZ4760_CLK_OTG_PHY	38
> +#define JZ4760_CLK_EXT512	39
> +#define JZ4760_CLK_RTC		40
> +#define JZ4760_CLK_LPCLK_DIV	41
> +#define JZ4760_CLK_TVE		42
> +#define JZ4760_CLK_LPCLK	43
> +
> +#endif /* __DT_BINDINGS_CLOCK_JZ4760_CGU_H__ */

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 6/6] clk: ingenic: Add support for the JZ4760
  2021-03-17 12:41   ` Zhou Yanjie
@ 2021-03-22 17:40     ` Paul Cercueil
  2021-03-23 15:41       ` Zhou Yanjie
  0 siblings, 1 reply; 16+ messages in thread
From: Paul Cercueil @ 2021-03-22 17:40 UTC (permalink / raw)
  To: Zhou Yanjie
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, od, linux-clk,
	devicetree, linux-kernel, linux-mips

Hi Zhou,

Le mer. 17 mars 2021 à 20:41, Zhou Yanjie <zhouyanjie@wanyeetech.com> 
a écrit :
> Hi Paul,
> 
> On 2021/3/7 下午10:17, Paul Cercueil wrote:
>> Add the CGU code and the compatible string to the TCU driver to 
>> support
>> the JZ4760 SoC.
>> 
>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>> ---
>>   drivers/clk/ingenic/Kconfig            |  10 +
>>   drivers/clk/ingenic/Makefile           |   1 +
>>   drivers/clk/ingenic/jz4760-cgu.c       | 433 
>> +++++++++++++++++++++++++
>>   drivers/clk/ingenic/tcu.c              |   2 +
>>   include/dt-bindings/clock/jz4760-cgu.h |  54 +++
>>   5 files changed, 500 insertions(+)
>>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>> 
>> diff --git a/drivers/clk/ingenic/Kconfig 
>> b/drivers/clk/ingenic/Kconfig
>> index 580b0cf69ed5..898f1bc478c9 100644
>> --- a/drivers/clk/ingenic/Kconfig
>> +++ b/drivers/clk/ingenic/Kconfig
>> @@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
>>   \x7f  	  If building for a JZ4725B SoC, you want to say Y here.
>>   \x7f+config INGENIC_CGU_JZ4760
>> +	bool "Ingenic JZ4760 CGU driver"
>> +	default MACH_JZ4760
>> +	select INGENIC_CGU_COMMON
>> +	help
>> +	  Support the clocks provided by the CGU hardware on Ingenic JZ4760
>> +	  and compatible SoCs.
>> +
>> +	  If building for a JZ4760 SoC, you want to say Y here.
>> +
>>   config INGENIC_CGU_JZ4770
>>   	bool "Ingenic JZ4770 CGU driver"
>>   	default MACH_JZ4770
>> diff --git a/drivers/clk/ingenic/Makefile 
>> b/drivers/clk/ingenic/Makefile
>> index aaa4bffe03c6..9edfaf4610b9 100644
>> --- a/drivers/clk/ingenic/Makefile
>> +++ b/drivers/clk/ingenic/Makefile
>> @@ -2,6 +2,7 @@
>>   obj-$(CONFIG_INGENIC_CGU_COMMON)	+= cgu.o pm.o
>>   obj-$(CONFIG_INGENIC_CGU_JZ4740)	+= jz4740-cgu.o
>>   obj-$(CONFIG_INGENIC_CGU_JZ4725B)	+= jz4725b-cgu.o
>> +obj-$(CONFIG_INGENIC_CGU_JZ4760)	+= jz4760-cgu.o
>>   obj-$(CONFIG_INGENIC_CGU_JZ4770)	+= jz4770-cgu.o
>>   obj-$(CONFIG_INGENIC_CGU_JZ4780)	+= jz4780-cgu.o
>>   obj-$(CONFIG_INGENIC_CGU_X1000)		+= x1000-cgu.o
>> diff --git a/drivers/clk/ingenic/jz4760-cgu.c 
>> b/drivers/clk/ingenic/jz4760-cgu.c
>> new file mode 100644
>> index 000000000000..a45327cba7d1
>> --- /dev/null
>> +++ b/drivers/clk/ingenic/jz4760-cgu.c
>> @@ -0,0 +1,433 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * JZ4760 SoC CGU driver
>> + * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
>> + */
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/delay.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +
>> +#include <linux/clk.h>
>> +
>> +#include <dt-bindings/clock/jz4760-cgu.h>
>> +
>> +#include "cgu.h"
>> +#include "pm.h"
>> +
>> +#define MHZ (1000 * 1000)
>> +
>> +/*
>> + * CPM registers offset address definition
>> + */
>> +#define CGU_REG_CPCCR		0x00
>> +#define CGU_REG_LCR		0x04
>> +#define CGU_REG_CPPCR0		0x10
>> +#define CGU_REG_CLKGR0		0x20
>> +#define CGU_REG_OPCR		0x24
>> +#define CGU_REG_CLKGR1		0x28
>> +#define CGU_REG_CPPCR1		0x30
>> +#define CGU_REG_USBPCR		0x3c
>> +#define CGU_REG_USBCDR		0x50
>> +#define CGU_REG_I2SCDR		0x60
>> +#define CGU_REG_LPCDR		0x64
>> +#define CGU_REG_MSCCDR		0x68
>> +#define CGU_REG_UHCCDR		0x6c
>> +#define CGU_REG_SSICDR		0x74
>> +#define CGU_REG_CIMCDR		0x7c
>> +#define CGU_REG_GPSCDR		0x80
>> +#define CGU_REG_PCMCDR		0x84
>> +#define CGU_REG_GPUCDR		0x88
>> +
>> +static const s8 pll_od_encoding[8] = {
>> +	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
>> +};
>> +
>> +static const u8 jz4760_cgu_cpccr_div_table[] = {
>> +	1, 2, 3, 4, 6, 8,
>> +};
>> +
>> +static const u8 jz4760_cgu_pll_half_div_table[] = {
>> +	2, 1,
>> +};
>> +
>> +static void
>> +jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
>> +		       unsigned long rate, unsigned long parent_rate,
>> +		       unsigned int *pm, unsigned int *pn, unsigned int *pod)
>> +{
>> +	unsigned int m, n, od;
>> +
>> +	/* The output of the PLL must be between 500 and 1500 MHz. */
>> +	rate = clamp_val(rate, 500ul * MHZ, 1500ul * MHZ);
>> +
>> +	/* The frequency after the N divider must be between 1 and 50 MHz. 
>> */
>> +	n = parent_rate / (1 * MHZ);
>> +
>> +	/* The N divider must be >= 2. */
>> +	n = clamp_val(n, 2, 1 << pll_info->n_bits);
>> +
>> +	for (;;) {
>> +		od = 0;
>> +
>> +		do {
>> +			m = (rate / MHZ) * ++od * n / (parent_rate / MHZ);
> 
> 
> Please correct me if I am wrong, according to the PM, when the 
> register value of OD is 0, 1, 2, 3, the value corresponding 
> participating PL frequency calculation is 1, 2, 4, 8. Therefore, 
> change
> 
> m = (rate / MHZ) * ++od * n / (parent_rate / MHZ); to m = (rate / 
> MHZ) * (2 ^ od++) * n / (parent_rate / MHZ); seems to be more 
> appropriate, it can avoid 3, 5, 6, and 7 that should not exist.

You are totally correct. I will send a revised version.

Thanks!

Cheers,
-Paul

>> +		} while (m < pll_info->m_offset || m & 1);
>> +
>> +		if (m <= (1 << pll_info->m_bits) - 2)
>> +			break;
>> +
>> +		n >>= 1;
>> +	}
>> +
>> +	*pm = m;
>> +	*pn = n;
>> +	*pod = od;
> 
> 
> If we change the above formula, we also need to change this to *pod = 
> 2 ^ od;
> 
> 
> Thanks and best regards!
> 
> 
>> +}
>> +
>> +static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
>> +
>> +	/* External clocks */
>> +
>> +	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
>> +	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
>> +
>> +	/* PLLs */
>> +
>> +	[JZ4760_CLK_PLL0] = {
>> +		"pll0", CGU_CLK_PLL,
>> +		.parents = { JZ4760_CLK_EXT },
>> +		.pll = {
>> +			.reg = CGU_REG_CPPCR0,
>> +			.rate_multiplier = 1,
>> +			.m_shift = 23,
>> +			.m_bits = 8,
>> +			.m_offset = 0,
>> +			.n_shift = 18,
>> +			.n_bits = 4,
>> +			.n_offset = 0,
>> +			.od_shift = 16,
>> +			.od_bits = 2,
>> +			.od_max = 8,
>> +			.od_encoding = pll_od_encoding,
>> +			.bypass_reg = CGU_REG_CPPCR0,
>> +			.bypass_bit = 9,
>> +			.enable_bit = 8,
>> +			.stable_bit = 10,
>> +			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
>> +		},
>> +	},
>> +
>> +	[JZ4760_CLK_PLL1] = {
>> +		/* TODO: PLL1 can depend on PLL0 */
>> +		"pll1", CGU_CLK_PLL,
>> +		.parents = { JZ4760_CLK_EXT },
>> +		.pll = {
>> +			.reg = CGU_REG_CPPCR1,
>> +			.rate_multiplier = 1,
>> +			.m_shift = 23,
>> +			.m_bits = 8,
>> +			.m_offset = 0,
>> +			.n_shift = 18,
>> +			.n_bits = 4,
>> +			.n_offset = 0,
>> +			.od_shift = 16,
>> +			.od_bits = 2,
>> +			.od_max = 8,
>> +			.od_encoding = pll_od_encoding,
>> +			.bypass_bit = -1,
>> +			.enable_bit = 7,
>> +			.stable_bit = 6,
>> +			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
>> +		},
>> +	},
>> +
>> +	/* Main clocks */
>> +
>> +	[JZ4760_CLK_CCLK] = {
>> +		"cclk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +	[JZ4760_CLK_HCLK] = {
>> +		"hclk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +	[JZ4760_CLK_SCLK] = {
>> +		"sclk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +	[JZ4760_CLK_H2CLK] = {
>> +		"h2clk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +	[JZ4760_CLK_MCLK] = {
>> +		"mclk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +	[JZ4760_CLK_PCLK] = {
>> +		"pclk", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0, },
>> +		.div = {
>> +			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
>> +			jz4760_cgu_cpccr_div_table,
>> +		},
>> +	},
>> +
>> +	/* Divided clocks */
>> +
>> +	[JZ4760_CLK_PLL0_HALF] = {
>> +		"pll0_half", CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_PLL0 },
>> +		.div = {
>> +			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
>> +			jz4760_cgu_pll_half_div_table,
>> +		},
>> +	},
>> +
>> +	/* Those divided clocks can connect to PLL0 or PLL1 */
>> +
>> +	[JZ4760_CLK_UHC] = {
>> +		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>> +		.mux = { CGU_REG_UHCCDR, 31, 1 },
>> +		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
>> +		.gate = { CGU_REG_CLKGR0, 24 },
>> +	},
>> +	[JZ4760_CLK_GPU] = {
>> +		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>> +		.mux = { CGU_REG_GPUCDR, 31, 1 },
>> +		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
>> +		.gate = { CGU_REG_CLKGR1, 9 },
>> +	},
>> +	[JZ4760_CLK_LPCLK_DIV] = {
>> +		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>> +		.mux = { CGU_REG_LPCDR, 29, 1 },
>> +		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
>> +	},
>> +	[JZ4760_CLK_TVE] = {
>> +		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
>> +		.mux = { CGU_REG_LPCDR, 31, 1 },
>> +		.gate = { CGU_REG_CLKGR0, 27 },
>> +	},
>> +	[JZ4760_CLK_LPCLK] = {
>> +		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
>> +		.mux = { CGU_REG_LPCDR, 30, 1 },
>> +		.gate = { CGU_REG_CLKGR0, 28 },
>> +	},
>> +	[JZ4760_CLK_GPS] = {
>> +		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>> +		.mux = { CGU_REG_GPSCDR, 31, 1 },
>> +		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
>> +		.gate = { CGU_REG_CLKGR0, 22 },
>> +	},
>> +
>> +	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
>> +
>> +	[JZ4760_CLK_PCM] = {
>> +		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_EXT, -1,
>> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>> +		.mux = { CGU_REG_PCMCDR, 30, 2 },
>> +		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>> +		.gate = { CGU_REG_CLKGR1, 8 },
>> +	},
>> +	[JZ4760_CLK_I2S] = {
>> +		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_EXT, -1,
>> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>> +		.mux = { CGU_REG_I2SCDR, 30, 2 },
>> +		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>> +	},
>> +	[JZ4760_CLK_OTG] = {
>> +		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_EXT, -1,
>> +			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>> +		.mux = { CGU_REG_USBCDR, 30, 2 },
>> +		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
>> +		.gate = { CGU_REG_CLKGR0, 2 },
>> +	},
>> +
>> +	/* Those divided clocks can connect to EXT or PLL0 */
>> +	[JZ4760_CLK_MMC_MUX] = {
>> +		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
>> +		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>> +		.mux = { CGU_REG_MSCCDR, 31, 1 },
>> +		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>> +	},
>> +	[JZ4760_CLK_SSI_MUX] = {
>> +		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>> +		.mux = { CGU_REG_SSICDR, 31, 1 },
>> +		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>> +	},
>> +
>> +	/* These divided clock can connect to PLL0 only */
>> +	[JZ4760_CLK_CIM] = {
>> +		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_PLL0_HALF },
>> +		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
>> +		.gate = { CGU_REG_CLKGR0, 26 },
>> +	},
>> +
>> +	/* Gate-only clocks */
>> +
>> +	[JZ4760_CLK_SSI0] = {
>> +		"ssi0", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_SSI_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 4 },
>> +	},
>> +	[JZ4760_CLK_SSI1] = {
>> +		"ssi1", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_SSI_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 19 },
>> +	},
>> +	[JZ4760_CLK_SSI2] = {
>> +		"ssi2", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_SSI_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 20 },
>> +	},
>> +	[JZ4760_CLK_DMA] = {
>> +		"dma", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_H2CLK, },
>> +		.gate = { CGU_REG_CLKGR0, 21 },
>> +	},
>> +	[JZ4760_CLK_I2C0] = {
>> +		"i2c0", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 5 },
>> +	},
>> +	[JZ4760_CLK_I2C1] = {
>> +		"i2c1", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 6 },
>> +	},
>> +	[JZ4760_CLK_UART0] = {
>> +		"uart0", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 15 },
>> +	},
>> +	[JZ4760_CLK_UART1] = {
>> +		"uart1", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 16 },
>> +	},
>> +	[JZ4760_CLK_UART2] = {
>> +		"uart2", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 17 },
>> +	},
>> +	[JZ4760_CLK_UART3] = {
>> +		"uart3", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 18 },
>> +	},
>> +	[JZ4760_CLK_IPU] = {
>> +		"ipu", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_HCLK, },
>> +		.gate = { CGU_REG_CLKGR0, 29 },
>> +	},
>> +	[JZ4760_CLK_ADC] = {
>> +		"adc", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 14 },
>> +	},
>> +	[JZ4760_CLK_AIC] = {
>> +		"aic", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_EXT, },
>> +		.gate = { CGU_REG_CLKGR0, 8 },
>> +	},
>> +	[JZ4760_CLK_VPU] = {
>> +		"vpu", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_HCLK, },
>> +		.gate = { CGU_REG_LCR, 30, false, 150 },
>> +	},
>> +	[JZ4760_CLK_MMC0] = {
>> +		"mmc0", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_MMC_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 3 },
>> +	},
>> +	[JZ4760_CLK_MMC1] = {
>> +		"mmc1", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_MMC_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 11 },
>> +	},
>> +	[JZ4760_CLK_MMC2] = {
>> +		"mmc2", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_MMC_MUX, },
>> +		.gate = { CGU_REG_CLKGR0, 12 },
>> +	},
>> +	[JZ4760_CLK_UHC_PHY] = {
>> +		"uhc_phy", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_UHC, },
>> +		.gate = { CGU_REG_OPCR, 5 },
>> +	},
>> +	[JZ4760_CLK_OTG_PHY] = {
>> +		"usb_phy", CGU_CLK_GATE,
>> +		.parents = { JZ4760_CLK_OTG },
>> +		.gate = { CGU_REG_OPCR, 7, true, 50 },
>> +	},
>> +
>> +	/* Custom clocks */
>> +	[JZ4760_CLK_EXT512] = {
>> +		"ext/512", CGU_CLK_FIXDIV,
>> +		.parents = { JZ4760_CLK_EXT },
>> +		.fixdiv = { 512 },
>> +	},
>> +	[JZ4760_CLK_RTC] = {
>> +		"rtc", CGU_CLK_MUX,
>> +		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
>> +		.mux = { CGU_REG_OPCR, 2, 1},
>> +	},
>> +};
>> +
>> +static void __init jz4760_cgu_init(struct device_node *np)
>> +{
>> +	struct ingenic_cgu *cgu;
>> +	int retval;
>> +
>> +	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
>> +			      ARRAY_SIZE(jz4760_cgu_clocks), np);
>> +	if (!cgu) {
>> +		pr_err("%s: failed to initialise CGU\n", __func__);
>> +		return;
>> +	}
>> +
>> +	retval = ingenic_cgu_register_clocks(cgu);
>> +	if (retval)
>> +		pr_err("%s: failed to register CGU Clocks\n", __func__);
>> +
>> +	ingenic_cgu_register_syscore_ops(cgu);
>> +}
>> +
>> +/* We only probe via devicetree, no need for a platform driver */
>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", 
>> jz4760_cgu_init);
>> +
>> +/* JZ4760B has some small differences, but we don't implement them. 
>> */
>> +CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", 
>> jz4760_cgu_init);
>> diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
>> index 9382dc3aa27e..77acfbeb4830 100644
>> --- a/drivers/clk/ingenic/tcu.c
>> +++ b/drivers/clk/ingenic/tcu.c
>> @@ -326,6 +326,7 @@ static const struct ingenic_soc_info 
>> x1000_soc_info = {
>>   static const struct of_device_id __maybe_unused 
>> ingenic_tcu_of_match[] __initconst = {
>>   	{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
>>   	{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, 
>> },
>> +	{ .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, },
>>   	{ .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, },
>>   	{ .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
>>   	{ /* sentinel */ }
>> @@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct 
>> device_node *np)
>>   \x7f  CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", 
>> ingenic_tcu_init);
>>   CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", 
>> ingenic_tcu_init);
>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", 
>> ingenic_tcu_init);
>>   CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", 
>> ingenic_tcu_init);
>>   CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", 
>> ingenic_tcu_init);
>> diff --git a/include/dt-bindings/clock/jz4760-cgu.h 
>> b/include/dt-bindings/clock/jz4760-cgu.h
>> new file mode 100644
>> index 000000000000..4bb2e19c4743
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/jz4760-cgu.h
>> @@ -0,0 +1,54 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * This header provides clock numbers for the ingenic,jz4760-cgu DT 
>> binding.
>> + */
>> +
>> +#ifndef __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>> +#define __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>> +
>> +#define JZ4760_CLK_EXT		0
>> +#define JZ4760_CLK_OSC32K	1
>> +#define JZ4760_CLK_PLL0		2
>> +#define JZ4760_CLK_PLL0_HALF	3
>> +#define JZ4760_CLK_PLL1		4
>> +#define JZ4760_CLK_CCLK		5
>> +#define JZ4760_CLK_HCLK		6
>> +#define JZ4760_CLK_SCLK		7
>> +#define JZ4760_CLK_H2CLK	8
>> +#define JZ4760_CLK_MCLK		9
>> +#define JZ4760_CLK_PCLK		10
>> +#define JZ4760_CLK_MMC_MUX	11
>> +#define JZ4760_CLK_MMC0		12
>> +#define JZ4760_CLK_MMC1		13
>> +#define JZ4760_CLK_MMC2		14
>> +#define JZ4760_CLK_CIM		15
>> +#define JZ4760_CLK_UHC		16
>> +#define JZ4760_CLK_GPU		17
>> +#define JZ4760_CLK_GPS		18
>> +#define JZ4760_CLK_SSI_MUX	19
>> +#define JZ4760_CLK_PCM		20
>> +#define JZ4760_CLK_I2S		21
>> +#define JZ4760_CLK_OTG		22
>> +#define JZ4760_CLK_SSI0		23
>> +#define JZ4760_CLK_SSI1		24
>> +#define JZ4760_CLK_SSI2		25
>> +#define JZ4760_CLK_DMA		26
>> +#define JZ4760_CLK_I2C0		27
>> +#define JZ4760_CLK_I2C1		28
>> +#define JZ4760_CLK_UART0	29
>> +#define JZ4760_CLK_UART1	30
>> +#define JZ4760_CLK_UART2	31
>> +#define JZ4760_CLK_UART3	32
>> +#define JZ4760_CLK_IPU		33
>> +#define JZ4760_CLK_ADC		34
>> +#define JZ4760_CLK_AIC		35
>> +#define JZ4760_CLK_VPU		36
>> +#define JZ4760_CLK_UHC_PHY	37
>> +#define JZ4760_CLK_OTG_PHY	38
>> +#define JZ4760_CLK_EXT512	39
>> +#define JZ4760_CLK_RTC		40
>> +#define JZ4760_CLK_LPCLK_DIV	41
>> +#define JZ4760_CLK_TVE		42
>> +#define JZ4760_CLK_LPCLK	43
>> +
>> +#endif /* __DT_BINDINGS_CLOCK_JZ4760_CGU_H__ */



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 6/6] clk: ingenic: Add support for the JZ4760
  2021-03-22 17:40     ` Paul Cercueil
@ 2021-03-23 15:41       ` Zhou Yanjie
  2021-03-23 15:55         ` Paul Cercueil
  0 siblings, 1 reply; 16+ messages in thread
From: Zhou Yanjie @ 2021-03-23 15:41 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, od, linux-clk,
	devicetree, linux-kernel, linux-mips

Hi Paul,

On 2021/3/23 上午1:40, Paul Cercueil wrote:
> Hi Zhou,
>
> Le mer. 17 mars 2021 à 20:41, Zhou Yanjie <zhouyanjie@wanyeetech.com> 
> a écrit :
>> Hi Paul,
>>
>> On 2021/3/7 下午10:17, Paul Cercueil wrote:
>>> Add the CGU code and the compatible string to the TCU driver to support
>>> the JZ4760 SoC.
>>>
>>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>>> ---
>>>   drivers/clk/ingenic/Kconfig            |  10 +
>>>   drivers/clk/ingenic/Makefile           |   1 +
>>>   drivers/clk/ingenic/jz4760-cgu.c       | 433 
>>> +++++++++++++++++++++++++
>>>   drivers/clk/ingenic/tcu.c              |   2 +
>>>   include/dt-bindings/clock/jz4760-cgu.h |  54 +++
>>>   5 files changed, 500 insertions(+)
>>>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>>>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>>>
>>> diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
>>> index 580b0cf69ed5..898f1bc478c9 100644
>>> --- a/drivers/clk/ingenic/Kconfig
>>> +++ b/drivers/clk/ingenic/Kconfig
>>> @@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
>>>   \x7f        If building for a JZ4725B SoC, you want to say Y here.
>>>   \x7f+config INGENIC_CGU_JZ4760
>>> +    bool "Ingenic JZ4760 CGU driver"
>>> +    default MACH_JZ4760
>>> +    select INGENIC_CGU_COMMON
>>> +    help
>>> +      Support the clocks provided by the CGU hardware on Ingenic 
>>> JZ4760
>>> +      and compatible SoCs.
>>> +
>>> +      If building for a JZ4760 SoC, you want to say Y here.
>>> +
>>>   config INGENIC_CGU_JZ4770
>>>       bool "Ingenic JZ4770 CGU driver"
>>>       default MACH_JZ4770
>>> diff --git a/drivers/clk/ingenic/Makefile 
>>> b/drivers/clk/ingenic/Makefile
>>> index aaa4bffe03c6..9edfaf4610b9 100644
>>> --- a/drivers/clk/ingenic/Makefile
>>> +++ b/drivers/clk/ingenic/Makefile
>>> @@ -2,6 +2,7 @@
>>>   obj-$(CONFIG_INGENIC_CGU_COMMON)    += cgu.o pm.o
>>>   obj-$(CONFIG_INGENIC_CGU_JZ4740)    += jz4740-cgu.o
>>>   obj-$(CONFIG_INGENIC_CGU_JZ4725B)    += jz4725b-cgu.o
>>> +obj-$(CONFIG_INGENIC_CGU_JZ4760)    += jz4760-cgu.o
>>>   obj-$(CONFIG_INGENIC_CGU_JZ4770)    += jz4770-cgu.o
>>>   obj-$(CONFIG_INGENIC_CGU_JZ4780)    += jz4780-cgu.o
>>>   obj-$(CONFIG_INGENIC_CGU_X1000)        += x1000-cgu.o
>>> diff --git a/drivers/clk/ingenic/jz4760-cgu.c 
>>> b/drivers/clk/ingenic/jz4760-cgu.c
>>> new file mode 100644
>>> index 000000000000..a45327cba7d1
>>> --- /dev/null
>>> +++ b/drivers/clk/ingenic/jz4760-cgu.c
>>> @@ -0,0 +1,433 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * JZ4760 SoC CGU driver
>>> + * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
>>> + */
>>> +
>>> +#include <linux/bitops.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/of.h>
>>> +
>>> +#include <linux/clk.h>
>>> +
>>> +#include <dt-bindings/clock/jz4760-cgu.h>
>>> +
>>> +#include "cgu.h"
>>> +#include "pm.h"
>>> +
>>> +#define MHZ (1000 * 1000)
>>> +
>>> +/*
>>> + * CPM registers offset address definition
>>> + */
>>> +#define CGU_REG_CPCCR        0x00
>>> +#define CGU_REG_LCR        0x04
>>> +#define CGU_REG_CPPCR0        0x10
>>> +#define CGU_REG_CLKGR0        0x20
>>> +#define CGU_REG_OPCR        0x24
>>> +#define CGU_REG_CLKGR1        0x28
>>> +#define CGU_REG_CPPCR1        0x30
>>> +#define CGU_REG_USBPCR        0x3c
>>> +#define CGU_REG_USBCDR        0x50
>>> +#define CGU_REG_I2SCDR        0x60
>>> +#define CGU_REG_LPCDR        0x64
>>> +#define CGU_REG_MSCCDR        0x68
>>> +#define CGU_REG_UHCCDR        0x6c
>>> +#define CGU_REG_SSICDR        0x74
>>> +#define CGU_REG_CIMCDR        0x7c
>>> +#define CGU_REG_GPSCDR        0x80
>>> +#define CGU_REG_PCMCDR        0x84
>>> +#define CGU_REG_GPUCDR        0x88
>>> +
>>> +static const s8 pll_od_encoding[8] = {
>>> +    0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
>>> +};
>>> +
>>> +static const u8 jz4760_cgu_cpccr_div_table[] = {
>>> +    1, 2, 3, 4, 6, 8,
>>> +};
>>> +
>>> +static const u8 jz4760_cgu_pll_half_div_table[] = {
>>> +    2, 1,
>>> +};
>>> +
>>> +static void
>>> +jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
>>> +               unsigned long rate, unsigned long parent_rate,
>>> +               unsigned int *pm, unsigned int *pn, unsigned int *pod)
>>> +{
>>> +    unsigned int m, n, od;
>>> +
>>> +    /* The output of the PLL must be between 500 and 1500 MHz. */
>>> +    rate = clamp_val(rate, 500ul * MHZ, 1500ul * MHZ);
>>> +
>>> +    /* The frequency after the N divider must be between 1 and 50 
>>> MHz. */
>>> +    n = parent_rate / (1 * MHZ);
>>> +
>>> +    /* The N divider must be >= 2. */
>>> +    n = clamp_val(n, 2, 1 << pll_info->n_bits);
>>> +
>>> +    for (;;) {
>>> +        od = 0;
>>> +
>>> +        do {
>>> +            m = (rate / MHZ) * ++od * n / (parent_rate / MHZ);
>>
>>
>> Please correct me if I am wrong, according to the PM, when the 
>> register value of OD is 0, 1, 2, 3, the value corresponding 
>> participating PL frequency calculation is 1, 2, 4, 8. Therefore, change
>>
>> m = (rate / MHZ) * ++od * n / (parent_rate / MHZ); to m = (rate / 
>> MHZ) * (2 ^ od++) * n / (parent_rate / MHZ); seems to be more 
>> appropriate, it can avoid 3, 5, 6, and 7 that should not exist.
>

I found a mistake. My brain must have been broken at that time. The 2 ^ 
od here I intended to express the meaning of od power of 2, but it 
should be written as 1 << od, otherwise it becomes a XOR operation.


> You are totally correct. I will send a revised version.
>
> Thanks!
>
> Cheers,
> -Paul
>
>>> +        } while (m < pll_info->m_offset || m & 1);
>>> +
>>> +        if (m <= (1 << pll_info->m_bits) - 2)
>>> +            break;
>>> +
>>> +        n >>= 1;
>>> +    }
>>> +
>>> +    *pm = m;
>>> +    *pn = n;
>>> +    *pod = od;
>>
>>
>> If we change the above formula, we also need to change this to *pod = 
>> 2 ^ od;
>>

Same here.


Thanks and best regards!


>>
>> Thanks and best regards!
>>
>>
>>> +}
>>> +
>>> +static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
>>> +
>>> +    /* External clocks */
>>> +
>>> +    [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
>>> +    [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
>>> +
>>> +    /* PLLs */
>>> +
>>> +    [JZ4760_CLK_PLL0] = {
>>> +        "pll0", CGU_CLK_PLL,
>>> +        .parents = { JZ4760_CLK_EXT },
>>> +        .pll = {
>>> +            .reg = CGU_REG_CPPCR0,
>>> +            .rate_multiplier = 1,
>>> +            .m_shift = 23,
>>> +            .m_bits = 8,
>>> +            .m_offset = 0,
>>> +            .n_shift = 18,
>>> +            .n_bits = 4,
>>> +            .n_offset = 0,
>>> +            .od_shift = 16,
>>> +            .od_bits = 2,
>>> +            .od_max = 8,
>>> +            .od_encoding = pll_od_encoding,
>>> +            .bypass_reg = CGU_REG_CPPCR0,
>>> +            .bypass_bit = 9,
>>> +            .enable_bit = 8,
>>> +            .stable_bit = 10,
>>> +            .calc_m_n_od = jz4760_cgu_calc_m_n_od,
>>> +        },
>>> +    },
>>> +
>>> +    [JZ4760_CLK_PLL1] = {
>>> +        /* TODO: PLL1 can depend on PLL0 */
>>> +        "pll1", CGU_CLK_PLL,
>>> +        .parents = { JZ4760_CLK_EXT },
>>> +        .pll = {
>>> +            .reg = CGU_REG_CPPCR1,
>>> +            .rate_multiplier = 1,
>>> +            .m_shift = 23,
>>> +            .m_bits = 8,
>>> +            .m_offset = 0,
>>> +            .n_shift = 18,
>>> +            .n_bits = 4,
>>> +            .n_offset = 0,
>>> +            .od_shift = 16,
>>> +            .od_bits = 2,
>>> +            .od_max = 8,
>>> +            .od_encoding = pll_od_encoding,
>>> +            .bypass_bit = -1,
>>> +            .enable_bit = 7,
>>> +            .stable_bit = 6,
>>> +            .calc_m_n_od = jz4760_cgu_calc_m_n_od,
>>> +        },
>>> +    },
>>> +
>>> +    /* Main clocks */
>>> +
>>> +    [JZ4760_CLK_CCLK] = {
>>> +        "cclk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +    [JZ4760_CLK_HCLK] = {
>>> +        "hclk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +    [JZ4760_CLK_SCLK] = {
>>> +        "sclk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +    [JZ4760_CLK_H2CLK] = {
>>> +        "h2clk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +    [JZ4760_CLK_MCLK] = {
>>> +        "mclk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +    [JZ4760_CLK_PCLK] = {
>>> +        "pclk", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0, },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
>>> +            jz4760_cgu_cpccr_div_table,
>>> +        },
>>> +    },
>>> +
>>> +    /* Divided clocks */
>>> +
>>> +    [JZ4760_CLK_PLL0_HALF] = {
>>> +        "pll0_half", CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_PLL0 },
>>> +        .div = {
>>> +            CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
>>> +            jz4760_cgu_pll_half_div_table,
>>> +        },
>>> +    },
>>> +
>>> +    /* Those divided clocks can connect to PLL0 or PLL1 */
>>> +
>>> +    [JZ4760_CLK_UHC] = {
>>> +        "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>> +        .mux = { CGU_REG_UHCCDR, 31, 1 },
>>> +        .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
>>> +        .gate = { CGU_REG_CLKGR0, 24 },
>>> +    },
>>> +    [JZ4760_CLK_GPU] = {
>>> +        "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>> +        .mux = { CGU_REG_GPUCDR, 31, 1 },
>>> +        .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
>>> +        .gate = { CGU_REG_CLKGR1, 9 },
>>> +    },
>>> +    [JZ4760_CLK_LPCLK_DIV] = {
>>> +        "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>> +        .mux = { CGU_REG_LPCDR, 29, 1 },
>>> +        .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
>>> +    },
>>> +    [JZ4760_CLK_TVE] = {
>>> +        "tve", CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
>>> +        .mux = { CGU_REG_LPCDR, 31, 1 },
>>> +        .gate = { CGU_REG_CLKGR0, 27 },
>>> +    },
>>> +    [JZ4760_CLK_LPCLK] = {
>>> +        "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
>>> +        .mux = { CGU_REG_LPCDR, 30, 1 },
>>> +        .gate = { CGU_REG_CLKGR0, 28 },
>>> +    },
>>> +    [JZ4760_CLK_GPS] = {
>>> +        "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>> +        .mux = { CGU_REG_GPSCDR, 31, 1 },
>>> +        .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
>>> +        .gate = { CGU_REG_CLKGR0, 22 },
>>> +    },
>>> +
>>> +    /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
>>> +
>>> +    [JZ4760_CLK_PCM] = {
>>> +        "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>> +        .mux = { CGU_REG_PCMCDR, 30, 2 },
>>> +        .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>>> +        .gate = { CGU_REG_CLKGR1, 8 },
>>> +    },
>>> +    [JZ4760_CLK_I2S] = {
>>> +        "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>> +        .mux = { CGU_REG_I2SCDR, 30, 2 },
>>> +        .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>>> +    },
>>> +    [JZ4760_CLK_OTG] = {
>>> +        "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>> +        .mux = { CGU_REG_USBCDR, 30, 2 },
>>> +        .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
>>> +        .gate = { CGU_REG_CLKGR0, 2 },
>>> +    },
>>> +
>>> +    /* Those divided clocks can connect to EXT or PLL0 */
>>> +    [JZ4760_CLK_MMC_MUX] = {
>>> +        "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
>>> +        .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>>> +        .mux = { CGU_REG_MSCCDR, 31, 1 },
>>> +        .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>>> +    },
>>> +    [JZ4760_CLK_SSI_MUX] = {
>>> +        "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>>> +        .mux = { CGU_REG_SSICDR, 31, 1 },
>>> +        .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>>> +    },
>>> +
>>> +    /* These divided clock can connect to PLL0 only */
>>> +    [JZ4760_CLK_CIM] = {
>>> +        "cim", CGU_CLK_DIV | CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_PLL0_HALF },
>>> +        .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
>>> +        .gate = { CGU_REG_CLKGR0, 26 },
>>> +    },
>>> +
>>> +    /* Gate-only clocks */
>>> +
>>> +    [JZ4760_CLK_SSI0] = {
>>> +        "ssi0", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 4 },
>>> +    },
>>> +    [JZ4760_CLK_SSI1] = {
>>> +        "ssi1", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 19 },
>>> +    },
>>> +    [JZ4760_CLK_SSI2] = {
>>> +        "ssi2", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 20 },
>>> +    },
>>> +    [JZ4760_CLK_DMA] = {
>>> +        "dma", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_H2CLK, },
>>> +        .gate = { CGU_REG_CLKGR0, 21 },
>>> +    },
>>> +    [JZ4760_CLK_I2C0] = {
>>> +        "i2c0", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 5 },
>>> +    },
>>> +    [JZ4760_CLK_I2C1] = {
>>> +        "i2c1", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 6 },
>>> +    },
>>> +    [JZ4760_CLK_UART0] = {
>>> +        "uart0", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 15 },
>>> +    },
>>> +    [JZ4760_CLK_UART1] = {
>>> +        "uart1", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 16 },
>>> +    },
>>> +    [JZ4760_CLK_UART2] = {
>>> +        "uart2", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 17 },
>>> +    },
>>> +    [JZ4760_CLK_UART3] = {
>>> +        "uart3", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 18 },
>>> +    },
>>> +    [JZ4760_CLK_IPU] = {
>>> +        "ipu", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_HCLK, },
>>> +        .gate = { CGU_REG_CLKGR0, 29 },
>>> +    },
>>> +    [JZ4760_CLK_ADC] = {
>>> +        "adc", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 14 },
>>> +    },
>>> +    [JZ4760_CLK_AIC] = {
>>> +        "aic", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_EXT, },
>>> +        .gate = { CGU_REG_CLKGR0, 8 },
>>> +    },
>>> +    [JZ4760_CLK_VPU] = {
>>> +        "vpu", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_HCLK, },
>>> +        .gate = { CGU_REG_LCR, 30, false, 150 },
>>> +    },
>>> +    [JZ4760_CLK_MMC0] = {
>>> +        "mmc0", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 3 },
>>> +    },
>>> +    [JZ4760_CLK_MMC1] = {
>>> +        "mmc1", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 11 },
>>> +    },
>>> +    [JZ4760_CLK_MMC2] = {
>>> +        "mmc2", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>> +        .gate = { CGU_REG_CLKGR0, 12 },
>>> +    },
>>> +    [JZ4760_CLK_UHC_PHY] = {
>>> +        "uhc_phy", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_UHC, },
>>> +        .gate = { CGU_REG_OPCR, 5 },
>>> +    },
>>> +    [JZ4760_CLK_OTG_PHY] = {
>>> +        "usb_phy", CGU_CLK_GATE,
>>> +        .parents = { JZ4760_CLK_OTG },
>>> +        .gate = { CGU_REG_OPCR, 7, true, 50 },
>>> +    },
>>> +
>>> +    /* Custom clocks */
>>> +    [JZ4760_CLK_EXT512] = {
>>> +        "ext/512", CGU_CLK_FIXDIV,
>>> +        .parents = { JZ4760_CLK_EXT },
>>> +        .fixdiv = { 512 },
>>> +    },
>>> +    [JZ4760_CLK_RTC] = {
>>> +        "rtc", CGU_CLK_MUX,
>>> +        .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
>>> +        .mux = { CGU_REG_OPCR, 2, 1},
>>> +    },
>>> +};
>>> +
>>> +static void __init jz4760_cgu_init(struct device_node *np)
>>> +{
>>> +    struct ingenic_cgu *cgu;
>>> +    int retval;
>>> +
>>> +    cgu = ingenic_cgu_new(jz4760_cgu_clocks,
>>> +                  ARRAY_SIZE(jz4760_cgu_clocks), np);
>>> +    if (!cgu) {
>>> +        pr_err("%s: failed to initialise CGU\n", __func__);
>>> +        return;
>>> +    }
>>> +
>>> +    retval = ingenic_cgu_register_clocks(cgu);
>>> +    if (retval)
>>> +        pr_err("%s: failed to register CGU Clocks\n", __func__);
>>> +
>>> +    ingenic_cgu_register_syscore_ops(cgu);
>>> +}
>>> +
>>> +/* We only probe via devicetree, no need for a platform driver */
>>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", 
>>> jz4760_cgu_init);
>>> +
>>> +/* JZ4760B has some small differences, but we don't implement them. */
>>> +CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", 
>>> jz4760_cgu_init);
>>> diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
>>> index 9382dc3aa27e..77acfbeb4830 100644
>>> --- a/drivers/clk/ingenic/tcu.c
>>> +++ b/drivers/clk/ingenic/tcu.c
>>> @@ -326,6 +326,7 @@ static const struct ingenic_soc_info 
>>> x1000_soc_info = {
>>>   static const struct of_device_id __maybe_unused 
>>> ingenic_tcu_of_match[] __initconst = {
>>>       { .compatible = "ingenic,jz4740-tcu", .data = 
>>> &jz4740_soc_info, },
>>>       { .compatible = "ingenic,jz4725b-tcu", .data = 
>>> &jz4725b_soc_info, },
>>> +    { .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, },
>>>       { .compatible = "ingenic,jz4770-tcu", .data = 
>>> &jz4770_soc_info, },
>>>       { .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
>>>       { /* sentinel */ }
>>> @@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct 
>>> device_node *np)
>>>   \x7f  CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", 
>>> ingenic_tcu_init);
>>>   CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", 
>>> ingenic_tcu_init);
>>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", 
>>> ingenic_tcu_init);
>>>   CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", 
>>> ingenic_tcu_init);
>>>   CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", 
>>> ingenic_tcu_init);
>>> diff --git a/include/dt-bindings/clock/jz4760-cgu.h 
>>> b/include/dt-bindings/clock/jz4760-cgu.h
>>> new file mode 100644
>>> index 000000000000..4bb2e19c4743
>>> --- /dev/null
>>> +++ b/include/dt-bindings/clock/jz4760-cgu.h
>>> @@ -0,0 +1,54 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/*
>>> + * This header provides clock numbers for the ingenic,jz4760-cgu DT 
>>> binding.
>>> + */
>>> +
>>> +#ifndef __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>>> +#define __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>>> +
>>> +#define JZ4760_CLK_EXT        0
>>> +#define JZ4760_CLK_OSC32K    1
>>> +#define JZ4760_CLK_PLL0        2
>>> +#define JZ4760_CLK_PLL0_HALF    3
>>> +#define JZ4760_CLK_PLL1        4
>>> +#define JZ4760_CLK_CCLK        5
>>> +#define JZ4760_CLK_HCLK        6
>>> +#define JZ4760_CLK_SCLK        7
>>> +#define JZ4760_CLK_H2CLK    8
>>> +#define JZ4760_CLK_MCLK        9
>>> +#define JZ4760_CLK_PCLK        10
>>> +#define JZ4760_CLK_MMC_MUX    11
>>> +#define JZ4760_CLK_MMC0        12
>>> +#define JZ4760_CLK_MMC1        13
>>> +#define JZ4760_CLK_MMC2        14
>>> +#define JZ4760_CLK_CIM        15
>>> +#define JZ4760_CLK_UHC        16
>>> +#define JZ4760_CLK_GPU        17
>>> +#define JZ4760_CLK_GPS        18
>>> +#define JZ4760_CLK_SSI_MUX    19
>>> +#define JZ4760_CLK_PCM        20
>>> +#define JZ4760_CLK_I2S        21
>>> +#define JZ4760_CLK_OTG        22
>>> +#define JZ4760_CLK_SSI0        23
>>> +#define JZ4760_CLK_SSI1        24
>>> +#define JZ4760_CLK_SSI2        25
>>> +#define JZ4760_CLK_DMA        26
>>> +#define JZ4760_CLK_I2C0        27
>>> +#define JZ4760_CLK_I2C1        28
>>> +#define JZ4760_CLK_UART0    29
>>> +#define JZ4760_CLK_UART1    30
>>> +#define JZ4760_CLK_UART2    31
>>> +#define JZ4760_CLK_UART3    32
>>> +#define JZ4760_CLK_IPU        33
>>> +#define JZ4760_CLK_ADC        34
>>> +#define JZ4760_CLK_AIC        35
>>> +#define JZ4760_CLK_VPU        36
>>> +#define JZ4760_CLK_UHC_PHY    37
>>> +#define JZ4760_CLK_OTG_PHY    38
>>> +#define JZ4760_CLK_EXT512    39
>>> +#define JZ4760_CLK_RTC        40
>>> +#define JZ4760_CLK_LPCLK_DIV    41
>>> +#define JZ4760_CLK_TVE        42
>>> +#define JZ4760_CLK_LPCLK    43
>>> +
>>> +#endif /* __DT_BINDINGS_CLOCK_JZ4760_CGU_H__ */
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 6/6] clk: ingenic: Add support for the JZ4760
  2021-03-23 15:41       ` Zhou Yanjie
@ 2021-03-23 15:55         ` Paul Cercueil
  0 siblings, 0 replies; 16+ messages in thread
From: Paul Cercueil @ 2021-03-23 15:55 UTC (permalink / raw)
  To: Zhou Yanjie
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, od, linux-clk,
	devicetree, linux-kernel, linux-mips

Hi Zhou,

Le mar. 23 mars 2021 à 23:41, Zhou Yanjie <zhouyanjie@wanyeetech.com> 
a écrit :
> Hi Paul,
> 
> On 2021/3/23 上午1:40, Paul Cercueil wrote:
>> Hi Zhou,
>> 
>> Le mer. 17 mars 2021 à 20:41, Zhou Yanjie 
>> <zhouyanjie@wanyeetech.com> \x7fa écrit :
>>> Hi Paul,
>>> 
>>> On 2021/3/7 下午10:17, Paul Cercueil wrote:
>>>> Add the CGU code and the compatible string to the TCU driver to 
>>>> support
>>>> the JZ4760 SoC.
>>>> 
>>>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>>>> ---
>>>>   drivers/clk/ingenic/Kconfig            |  10 +
>>>>   drivers/clk/ingenic/Makefile           |   1 +
>>>>   drivers/clk/ingenic/jz4760-cgu.c       | 433 
>>>> \x7f\x7f\x7f+++++++++++++++++++++++++
>>>>   drivers/clk/ingenic/tcu.c              |   2 +
>>>>   include/dt-bindings/clock/jz4760-cgu.h |  54 +++
>>>>   5 files changed, 500 insertions(+)
>>>>   create mode 100644 drivers/clk/ingenic/jz4760-cgu.c
>>>>   create mode 100644 include/dt-bindings/clock/jz4760-cgu.h
>>>> 
>>>> diff --git a/drivers/clk/ingenic/Kconfig 
>>>> b/drivers/clk/ingenic/Kconfig
>>>> index 580b0cf69ed5..898f1bc478c9 100644
>>>> --- a/drivers/clk/ingenic/Kconfig
>>>> +++ b/drivers/clk/ingenic/Kconfig
>>>> @@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
>>>>   \x7f        If building for a JZ4725B SoC, you want to say Y here.
>>>>   \x7f+config INGENIC_CGU_JZ4760
>>>> +    bool "Ingenic JZ4760 CGU driver"
>>>> +    default MACH_JZ4760
>>>> +    select INGENIC_CGU_COMMON
>>>> +    help
>>>> +      Support the clocks provided by the CGU hardware on Ingenic 
>>>> \x7f\x7f\x7fJZ4760
>>>> +      and compatible SoCs.
>>>> +
>>>> +      If building for a JZ4760 SoC, you want to say Y here.
>>>> +
>>>>   config INGENIC_CGU_JZ4770
>>>>       bool "Ingenic JZ4770 CGU driver"
>>>>       default MACH_JZ4770
>>>> diff --git a/drivers/clk/ingenic/Makefile 
>>>> \x7f\x7f\x7fb/drivers/clk/ingenic/Makefile
>>>> index aaa4bffe03c6..9edfaf4610b9 100644
>>>> --- a/drivers/clk/ingenic/Makefile
>>>> +++ b/drivers/clk/ingenic/Makefile
>>>> @@ -2,6 +2,7 @@
>>>>   obj-$(CONFIG_INGENIC_CGU_COMMON)    += cgu.o pm.o
>>>>   obj-$(CONFIG_INGENIC_CGU_JZ4740)    += jz4740-cgu.o
>>>>   obj-$(CONFIG_INGENIC_CGU_JZ4725B)    += jz4725b-cgu.o
>>>> +obj-$(CONFIG_INGENIC_CGU_JZ4760)    += jz4760-cgu.o
>>>>   obj-$(CONFIG_INGENIC_CGU_JZ4770)    += jz4770-cgu.o
>>>>   obj-$(CONFIG_INGENIC_CGU_JZ4780)    += jz4780-cgu.o
>>>>   obj-$(CONFIG_INGENIC_CGU_X1000)        += x1000-cgu.o
>>>> diff --git a/drivers/clk/ingenic/jz4760-cgu.c 
>>>> \x7f\x7f\x7fb/drivers/clk/ingenic/jz4760-cgu.c
>>>> new file mode 100644
>>>> index 000000000000..a45327cba7d1
>>>> --- /dev/null
>>>> +++ b/drivers/clk/ingenic/jz4760-cgu.c
>>>> @@ -0,0 +1,433 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * JZ4760 SoC CGU driver
>>>> + * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
>>>> + */
>>>> +
>>>> +#include <linux/bitops.h>
>>>> +#include <linux/clk-provider.h>
>>>> +#include <linux/delay.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/of.h>
>>>> +
>>>> +#include <linux/clk.h>
>>>> +
>>>> +#include <dt-bindings/clock/jz4760-cgu.h>
>>>> +
>>>> +#include "cgu.h"
>>>> +#include "pm.h"
>>>> +
>>>> +#define MHZ (1000 * 1000)
>>>> +
>>>> +/*
>>>> + * CPM registers offset address definition
>>>> + */
>>>> +#define CGU_REG_CPCCR        0x00
>>>> +#define CGU_REG_LCR        0x04
>>>> +#define CGU_REG_CPPCR0        0x10
>>>> +#define CGU_REG_CLKGR0        0x20
>>>> +#define CGU_REG_OPCR        0x24
>>>> +#define CGU_REG_CLKGR1        0x28
>>>> +#define CGU_REG_CPPCR1        0x30
>>>> +#define CGU_REG_USBPCR        0x3c
>>>> +#define CGU_REG_USBCDR        0x50
>>>> +#define CGU_REG_I2SCDR        0x60
>>>> +#define CGU_REG_LPCDR        0x64
>>>> +#define CGU_REG_MSCCDR        0x68
>>>> +#define CGU_REG_UHCCDR        0x6c
>>>> +#define CGU_REG_SSICDR        0x74
>>>> +#define CGU_REG_CIMCDR        0x7c
>>>> +#define CGU_REG_GPSCDR        0x80
>>>> +#define CGU_REG_PCMCDR        0x84
>>>> +#define CGU_REG_GPUCDR        0x88
>>>> +
>>>> +static const s8 pll_od_encoding[8] = {
>>>> +    0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
>>>> +};
>>>> +
>>>> +static const u8 jz4760_cgu_cpccr_div_table[] = {
>>>> +    1, 2, 3, 4, 6, 8,
>>>> +};
>>>> +
>>>> +static const u8 jz4760_cgu_pll_half_div_table[] = {
>>>> +    2, 1,
>>>> +};
>>>> +
>>>> +static void
>>>> +jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info 
>>>> *pll_info,
>>>> +               unsigned long rate, unsigned long parent_rate,
>>>> +               unsigned int *pm, unsigned int *pn, unsigned int 
>>>> *pod)
>>>> +{
>>>> +    unsigned int m, n, od;
>>>> +
>>>> +    /* The output of the PLL must be between 500 and 1500 MHz. */
>>>> +    rate = clamp_val(rate, 500ul * MHZ, 1500ul * MHZ);
>>>> +
>>>> +    /* The frequency after the N divider must be between 1 and 50 
>>>> \x7f\x7f\x7fMHz. */
>>>> +    n = parent_rate / (1 * MHZ);
>>>> +
>>>> +    /* The N divider must be >= 2. */
>>>> +    n = clamp_val(n, 2, 1 << pll_info->n_bits);
>>>> +
>>>> +    for (;;) {
>>>> +        od = 0;
>>>> +
>>>> +        do {
>>>> +            m = (rate / MHZ) * ++od * n / (parent_rate / MHZ);
>>> 
>>> 
>>> Please correct me if I am wrong, according to the PM, when the 
>>> \x7f\x7fregister value of OD is 0, 1, 2, 3, the value corresponding 
>>> \x7f\x7fparticipating PL frequency calculation is 1, 2, 4, 8. Therefore, 
>>> change
>>> 
>>> m = (rate / MHZ) * ++od * n / (parent_rate / MHZ); to m = (rate / 
>>> \x7f\x7fMHZ) * (2 ^ od++) * n / (parent_rate / MHZ); seems to be more 
>>> \x7f\x7fappropriate, it can avoid 3, 5, 6, and 7 that should not exist.
>> 
> 
> I found a mistake. My brain must have been broken at that time. The 2 
> ^ od here I intended to express the meaning of od power of 2, but it 
> should be written as 1 << od, otherwise it becomes a XOR operation.

Yes, don't worry - I understood it as (1 << od).

I'll send a v2 soon.

Cheers,
-Paul

>> You are totally correct. I will send a revised version.
>> 
>> Thanks!
>> 
>> Cheers,
>> -Paul
>> 
>>>> +        } while (m < pll_info->m_offset || m & 1);
>>>> +
>>>> +        if (m <= (1 << pll_info->m_bits) - 2)
>>>> +            break;
>>>> +
>>>> +        n >>= 1;
>>>> +    }
>>>> +
>>>> +    *pm = m;
>>>> +    *pn = n;
>>>> +    *pod = od;
>>> 
>>> 
>>> If we change the above formula, we also need to change this to *pod 
>>> = \x7f\x7f2 ^ od;
>>> 
> 
> Same here.
> 
> 
> Thanks and best regards!
> 
> 
>>> 
>>> Thanks and best regards!
>>> 
>>> 
>>>> +}
>>>> +
>>>> +static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
>>>> +
>>>> +    /* External clocks */
>>>> +
>>>> +    [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
>>>> +    [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
>>>> +
>>>> +    /* PLLs */
>>>> +
>>>> +    [JZ4760_CLK_PLL0] = {
>>>> +        "pll0", CGU_CLK_PLL,
>>>> +        .parents = { JZ4760_CLK_EXT },
>>>> +        .pll = {
>>>> +            .reg = CGU_REG_CPPCR0,
>>>> +            .rate_multiplier = 1,
>>>> +            .m_shift = 23,
>>>> +            .m_bits = 8,
>>>> +            .m_offset = 0,
>>>> +            .n_shift = 18,
>>>> +            .n_bits = 4,
>>>> +            .n_offset = 0,
>>>> +            .od_shift = 16,
>>>> +            .od_bits = 2,
>>>> +            .od_max = 8,
>>>> +            .od_encoding = pll_od_encoding,
>>>> +            .bypass_reg = CGU_REG_CPPCR0,
>>>> +            .bypass_bit = 9,
>>>> +            .enable_bit = 8,
>>>> +            .stable_bit = 10,
>>>> +            .calc_m_n_od = jz4760_cgu_calc_m_n_od,
>>>> +        },
>>>> +    },
>>>> +
>>>> +    [JZ4760_CLK_PLL1] = {
>>>> +        /* TODO: PLL1 can depend on PLL0 */
>>>> +        "pll1", CGU_CLK_PLL,
>>>> +        .parents = { JZ4760_CLK_EXT },
>>>> +        .pll = {
>>>> +            .reg = CGU_REG_CPPCR1,
>>>> +            .rate_multiplier = 1,
>>>> +            .m_shift = 23,
>>>> +            .m_bits = 8,
>>>> +            .m_offset = 0,
>>>> +            .n_shift = 18,
>>>> +            .n_bits = 4,
>>>> +            .n_offset = 0,
>>>> +            .od_shift = 16,
>>>> +            .od_bits = 2,
>>>> +            .od_max = 8,
>>>> +            .od_encoding = pll_od_encoding,
>>>> +            .bypass_bit = -1,
>>>> +            .enable_bit = 7,
>>>> +            .stable_bit = 6,
>>>> +            .calc_m_n_od = jz4760_cgu_calc_m_n_od,
>>>> +        },
>>>> +    },
>>>> +
>>>> +    /* Main clocks */
>>>> +
>>>> +    [JZ4760_CLK_CCLK] = {
>>>> +        "cclk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +    [JZ4760_CLK_HCLK] = {
>>>> +        "hclk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +    [JZ4760_CLK_SCLK] = {
>>>> +        "sclk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +    [JZ4760_CLK_H2CLK] = {
>>>> +        "h2clk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +    [JZ4760_CLK_MCLK] = {
>>>> +        "mclk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +    [JZ4760_CLK_PCLK] = {
>>>> +        "pclk", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0, },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
>>>> +            jz4760_cgu_cpccr_div_table,
>>>> +        },
>>>> +    },
>>>> +
>>>> +    /* Divided clocks */
>>>> +
>>>> +    [JZ4760_CLK_PLL0_HALF] = {
>>>> +        "pll0_half", CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_PLL0 },
>>>> +        .div = {
>>>> +            CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
>>>> +            jz4760_cgu_pll_half_div_table,
>>>> +        },
>>>> +    },
>>>> +
>>>> +    /* Those divided clocks can connect to PLL0 or PLL1 */
>>>> +
>>>> +    [JZ4760_CLK_UHC] = {
>>>> +        "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>>> +        .mux = { CGU_REG_UHCCDR, 31, 1 },
>>>> +        .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 24 },
>>>> +    },
>>>> +    [JZ4760_CLK_GPU] = {
>>>> +        "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>>> +        .mux = { CGU_REG_GPUCDR, 31, 1 },
>>>> +        .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
>>>> +        .gate = { CGU_REG_CLKGR1, 9 },
>>>> +    },
>>>> +    [JZ4760_CLK_LPCLK_DIV] = {
>>>> +        "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>>> +        .mux = { CGU_REG_LPCDR, 29, 1 },
>>>> +        .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
>>>> +    },
>>>> +    [JZ4760_CLK_TVE] = {
>>>> +        "tve", CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
>>>> +        .mux = { CGU_REG_LPCDR, 31, 1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 27 },
>>>> +    },
>>>> +    [JZ4760_CLK_LPCLK] = {
>>>> +        "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
>>>> +        .mux = { CGU_REG_LPCDR, 30, 1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 28 },
>>>> +    },
>>>> +    [JZ4760_CLK_GPS] = {
>>>> +        "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
>>>> +        .mux = { CGU_REG_GPSCDR, 31, 1 },
>>>> +        .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 22 },
>>>> +    },
>>>> +
>>>> +    /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
>>>> +
>>>> +    [JZ4760_CLK_PCM] = {
>>>> +        "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>>> +        .mux = { CGU_REG_PCMCDR, 30, 2 },
>>>> +        .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>>>> +        .gate = { CGU_REG_CLKGR1, 8 },
>>>> +    },
>>>> +    [JZ4760_CLK_I2S] = {
>>>> +        "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>>> +        .mux = { CGU_REG_I2SCDR, 30, 2 },
>>>> +        .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
>>>> +    },
>>>> +    [JZ4760_CLK_OTG] = {
>>>> +        "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_EXT, -1,
>>>> +            JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
>>>> +        .mux = { CGU_REG_USBCDR, 30, 2 },
>>>> +        .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 2 },
>>>> +    },
>>>> +
>>>> +    /* Those divided clocks can connect to EXT or PLL0 */
>>>> +    [JZ4760_CLK_MMC_MUX] = {
>>>> +        "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
>>>> +        .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>>>> +        .mux = { CGU_REG_MSCCDR, 31, 1 },
>>>> +        .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>>>> +    },
>>>> +    [JZ4760_CLK_SSI_MUX] = {
>>>> +        "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
>>>> +        .mux = { CGU_REG_SSICDR, 31, 1 },
>>>> +        .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
>>>> +    },
>>>> +
>>>> +    /* These divided clock can connect to PLL0 only */
>>>> +    [JZ4760_CLK_CIM] = {
>>>> +        "cim", CGU_CLK_DIV | CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_PLL0_HALF },
>>>> +        .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
>>>> +        .gate = { CGU_REG_CLKGR0, 26 },
>>>> +    },
>>>> +
>>>> +    /* Gate-only clocks */
>>>> +
>>>> +    [JZ4760_CLK_SSI0] = {
>>>> +        "ssi0", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 4 },
>>>> +    },
>>>> +    [JZ4760_CLK_SSI1] = {
>>>> +        "ssi1", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 19 },
>>>> +    },
>>>> +    [JZ4760_CLK_SSI2] = {
>>>> +        "ssi2", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_SSI_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 20 },
>>>> +    },
>>>> +    [JZ4760_CLK_DMA] = {
>>>> +        "dma", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_H2CLK, },
>>>> +        .gate = { CGU_REG_CLKGR0, 21 },
>>>> +    },
>>>> +    [JZ4760_CLK_I2C0] = {
>>>> +        "i2c0", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 5 },
>>>> +    },
>>>> +    [JZ4760_CLK_I2C1] = {
>>>> +        "i2c1", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 6 },
>>>> +    },
>>>> +    [JZ4760_CLK_UART0] = {
>>>> +        "uart0", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 15 },
>>>> +    },
>>>> +    [JZ4760_CLK_UART1] = {
>>>> +        "uart1", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 16 },
>>>> +    },
>>>> +    [JZ4760_CLK_UART2] = {
>>>> +        "uart2", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 17 },
>>>> +    },
>>>> +    [JZ4760_CLK_UART3] = {
>>>> +        "uart3", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 18 },
>>>> +    },
>>>> +    [JZ4760_CLK_IPU] = {
>>>> +        "ipu", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_HCLK, },
>>>> +        .gate = { CGU_REG_CLKGR0, 29 },
>>>> +    },
>>>> +    [JZ4760_CLK_ADC] = {
>>>> +        "adc", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 14 },
>>>> +    },
>>>> +    [JZ4760_CLK_AIC] = {
>>>> +        "aic", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_EXT, },
>>>> +        .gate = { CGU_REG_CLKGR0, 8 },
>>>> +    },
>>>> +    [JZ4760_CLK_VPU] = {
>>>> +        "vpu", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_HCLK, },
>>>> +        .gate = { CGU_REG_LCR, 30, false, 150 },
>>>> +    },
>>>> +    [JZ4760_CLK_MMC0] = {
>>>> +        "mmc0", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 3 },
>>>> +    },
>>>> +    [JZ4760_CLK_MMC1] = {
>>>> +        "mmc1", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 11 },
>>>> +    },
>>>> +    [JZ4760_CLK_MMC2] = {
>>>> +        "mmc2", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_MMC_MUX, },
>>>> +        .gate = { CGU_REG_CLKGR0, 12 },
>>>> +    },
>>>> +    [JZ4760_CLK_UHC_PHY] = {
>>>> +        "uhc_phy", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_UHC, },
>>>> +        .gate = { CGU_REG_OPCR, 5 },
>>>> +    },
>>>> +    [JZ4760_CLK_OTG_PHY] = {
>>>> +        "usb_phy", CGU_CLK_GATE,
>>>> +        .parents = { JZ4760_CLK_OTG },
>>>> +        .gate = { CGU_REG_OPCR, 7, true, 50 },
>>>> +    },
>>>> +
>>>> +    /* Custom clocks */
>>>> +    [JZ4760_CLK_EXT512] = {
>>>> +        "ext/512", CGU_CLK_FIXDIV,
>>>> +        .parents = { JZ4760_CLK_EXT },
>>>> +        .fixdiv = { 512 },
>>>> +    },
>>>> +    [JZ4760_CLK_RTC] = {
>>>> +        "rtc", CGU_CLK_MUX,
>>>> +        .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
>>>> +        .mux = { CGU_REG_OPCR, 2, 1},
>>>> +    },
>>>> +};
>>>> +
>>>> +static void __init jz4760_cgu_init(struct device_node *np)
>>>> +{
>>>> +    struct ingenic_cgu *cgu;
>>>> +    int retval;
>>>> +
>>>> +    cgu = ingenic_cgu_new(jz4760_cgu_clocks,
>>>> +                  ARRAY_SIZE(jz4760_cgu_clocks), np);
>>>> +    if (!cgu) {
>>>> +        pr_err("%s: failed to initialise CGU\n", __func__);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    retval = ingenic_cgu_register_clocks(cgu);
>>>> +    if (retval)
>>>> +        pr_err("%s: failed to register CGU Clocks\n", __func__);
>>>> +
>>>> +    ingenic_cgu_register_syscore_ops(cgu);
>>>> +}
>>>> +
>>>> +/* We only probe via devicetree, no need for a platform driver */
>>>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", 
>>>> \x7f\x7f\x7fjz4760_cgu_init);
>>>> +
>>>> +/* JZ4760B has some small differences, but we don't implement 
>>>> them. */
>>>> +CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", 
>>>> \x7f\x7f\x7fjz4760_cgu_init);
>>>> diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
>>>> index 9382dc3aa27e..77acfbeb4830 100644
>>>> --- a/drivers/clk/ingenic/tcu.c
>>>> +++ b/drivers/clk/ingenic/tcu.c
>>>> @@ -326,6 +326,7 @@ static const struct ingenic_soc_info 
>>>> \x7f\x7f\x7fx1000_soc_info = {
>>>>   static const struct of_device_id __maybe_unused 
>>>> \x7f\x7f\x7fingenic_tcu_of_match[] __initconst = {
>>>>       { .compatible = "ingenic,jz4740-tcu", .data = 
>>>> \x7f\x7f\x7f&jz4740_soc_info, },
>>>>       { .compatible = "ingenic,jz4725b-tcu", .data = 
>>>> \x7f\x7f\x7f&jz4725b_soc_info, },
>>>> +    { .compatible = "ingenic,jz4760-tcu", .data = 
>>>> &jz4770_soc_info, },
>>>>       { .compatible = "ingenic,jz4770-tcu", .data = 
>>>> \x7f\x7f\x7f&jz4770_soc_info, },
>>>>       { .compatible = "ingenic,x1000-tcu", .data = 
>>>> &x1000_soc_info, },
>>>>       { /* sentinel */ }
>>>> @@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct 
>>>> \x7f\x7f\x7fdevice_node *np)
>>>>   \x7f  CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", 
>>>> \x7f\x7f\x7fingenic_tcu_init);
>>>>   CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", 
>>>> \x7f\x7f\x7fingenic_tcu_init);
>>>> +CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", 
>>>> \x7f\x7f\x7fingenic_tcu_init);
>>>>   CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", 
>>>> \x7f\x7f\x7fingenic_tcu_init);
>>>>   CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", 
>>>> \x7f\x7f\x7fingenic_tcu_init);
>>>> diff --git a/include/dt-bindings/clock/jz4760-cgu.h 
>>>> \x7f\x7f\x7fb/include/dt-bindings/clock/jz4760-cgu.h
>>>> new file mode 100644
>>>> index 000000000000..4bb2e19c4743
>>>> --- /dev/null
>>>> +++ b/include/dt-bindings/clock/jz4760-cgu.h
>>>> @@ -0,0 +1,54 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/*
>>>> + * This header provides clock numbers for the ingenic,jz4760-cgu 
>>>> DT \x7f\x7f\x7fbinding.
>>>> + */
>>>> +
>>>> +#ifndef __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>>>> +#define __DT_BINDINGS_CLOCK_JZ4760_CGU_H__
>>>> +
>>>> +#define JZ4760_CLK_EXT        0
>>>> +#define JZ4760_CLK_OSC32K    1
>>>> +#define JZ4760_CLK_PLL0        2
>>>> +#define JZ4760_CLK_PLL0_HALF    3
>>>> +#define JZ4760_CLK_PLL1        4
>>>> +#define JZ4760_CLK_CCLK        5
>>>> +#define JZ4760_CLK_HCLK        6
>>>> +#define JZ4760_CLK_SCLK        7
>>>> +#define JZ4760_CLK_H2CLK    8
>>>> +#define JZ4760_CLK_MCLK        9
>>>> +#define JZ4760_CLK_PCLK        10
>>>> +#define JZ4760_CLK_MMC_MUX    11
>>>> +#define JZ4760_CLK_MMC0        12
>>>> +#define JZ4760_CLK_MMC1        13
>>>> +#define JZ4760_CLK_MMC2        14
>>>> +#define JZ4760_CLK_CIM        15
>>>> +#define JZ4760_CLK_UHC        16
>>>> +#define JZ4760_CLK_GPU        17
>>>> +#define JZ4760_CLK_GPS        18
>>>> +#define JZ4760_CLK_SSI_MUX    19
>>>> +#define JZ4760_CLK_PCM        20
>>>> +#define JZ4760_CLK_I2S        21
>>>> +#define JZ4760_CLK_OTG        22
>>>> +#define JZ4760_CLK_SSI0        23
>>>> +#define JZ4760_CLK_SSI1        24
>>>> +#define JZ4760_CLK_SSI2        25
>>>> +#define JZ4760_CLK_DMA        26
>>>> +#define JZ4760_CLK_I2C0        27
>>>> +#define JZ4760_CLK_I2C1        28
>>>> +#define JZ4760_CLK_UART0    29
>>>> +#define JZ4760_CLK_UART1    30
>>>> +#define JZ4760_CLK_UART2    31
>>>> +#define JZ4760_CLK_UART3    32
>>>> +#define JZ4760_CLK_IPU        33
>>>> +#define JZ4760_CLK_ADC        34
>>>> +#define JZ4760_CLK_AIC        35
>>>> +#define JZ4760_CLK_VPU        36
>>>> +#define JZ4760_CLK_UHC_PHY    37
>>>> +#define JZ4760_CLK_OTG_PHY    38
>>>> +#define JZ4760_CLK_EXT512    39
>>>> +#define JZ4760_CLK_RTC        40
>>>> +#define JZ4760_CLK_LPCLK_DIV    41
>>>> +#define JZ4760_CLK_TVE        42
>>>> +#define JZ4760_CLK_LPCLK    43
>>>> +
>>>> +#endif /* __DT_BINDINGS_CLOCK_JZ4760_CGU_H__ */
>> 



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-03-23 15:56 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-07 14:17 [PATCH 0/6] clk: Ingenic JZ4760(B) support Paul Cercueil
2021-03-07 14:17 ` [PATCH 1/6] dt-bindings: clock: ingenic: Add ingenic,jz4760{,b}-cgu compatibles Paul Cercueil
2021-03-08 22:56   ` Rob Herring
2021-03-07 14:17 ` [PATCH 2/6] clk: Support bypassing dividers Paul Cercueil
2021-03-07 14:17 ` [PATCH 3/6] clk: ingenic: Read bypass register only when there is one Paul Cercueil
2021-03-07 14:17 ` [PATCH 4/6] clk: ingenic: Remove pll_info.no_bypass_bit Paul Cercueil
2021-03-07 14:17 ` [PATCH 5/6] clk: ingenic: Support overriding PLLs M/N/OD calc algorithm Paul Cercueil
2021-03-10 14:42   ` Zhou Yanjie
2021-03-07 14:17 ` [PATCH 6/6] clk: ingenic: Add support for the JZ4760 Paul Cercueil
2021-03-17 12:41   ` Zhou Yanjie
2021-03-22 17:40     ` Paul Cercueil
2021-03-23 15:41       ` Zhou Yanjie
2021-03-23 15:55         ` Paul Cercueil
2021-03-09  6:31 ` [PATCH 0/6] clk: Ingenic JZ4760(B) support Zhou Yanjie
2021-03-09 15:33 ` Zhou Yanjie
2021-03-10 14:40 ` Zhou Yanjie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).