* [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support
@ 2026-10-25 19:18 H. Nikolaus Schaller
2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: H. Nikolaus Schaller @ 2026-10-25 19:18 UTC (permalink / raw)
To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Paul Cercueil
Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel,
kernel, H. Nikolaus Schaller
PATCH V1 2026-10-25 20:18:26:
This patch series introduces hardware support for the Clock Generation Unit
(CGU) and the Timer Clock Unit (TCU) found in the Ingenic X1600 SoC.
To achieve this cleanly, the common Ingenic clock and timer infrastructure
is modernized and parameterized.
As a side effect of making the core structures flexible enough to handle
the architectural layout of the X1600, it became straightforward to fully
integrate support for the legacy JZ4730 SoC later.
The series is structured as follows:
Patch 1: Adds the device tree bindings and clock definitions for the X1600,
incorporating the specific I2S handling, routing, and RX/TX gates.
Patch 2: Implements the Ingenic X1600 CGU clock driver. It updates the common
CGU core framework to support secondary post-VCO dividers (OD1),
and bypasses the lack of compound divider support via explicit
mdiv/nddiv handling for the I2S clocks.
Patch 3&4: Adapt the existing JZ4760 and X1000 CGU drivers to match the expanded
signature of the calc_m_n_od() callback from Patch 2, preventing
compilation breakages.
The changes have been successfully tested on CI20 (JZ4780), LX16 (X1600).
And on LX20 (X2000), LX26 (X2600) boards (with additional, specific patches).
H. Nikolaus Schaller (3):
dt-bindings: clock: Add Ingenic X1600 CGU bindings
clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework
changes
clk: ingenic: x1000-cgu: Adapt calc_m_n_od() to core framework changes
Paul Boddie (1):
clk: ingenic: Add Ingenic X1600 CGU clock driver support
.../bindings/clock/ingenic,cgu.yaml | 2 +
drivers/clk/ingenic/Kconfig | 10 +
drivers/clk/ingenic/Makefile | 1 +
drivers/clk/ingenic/cgu.c | 150 ++++--
drivers/clk/ingenic/cgu.h | 42 +-
drivers/clk/ingenic/jz4760-cgu.c | 3 +-
drivers/clk/ingenic/x1000-cgu.c | 3 +-
drivers/clk/ingenic/x1600-cgu.c | 476 ++++++++++++++++++
include/dt-bindings/clock/ingenic,x1600-cgu.h | 64 +++
9 files changed, 716 insertions(+), 35 deletions(-)
create mode 100644 drivers/clk/ingenic/x1600-cgu.c
create mode 100644 include/dt-bindings/clock/ingenic,x1600-cgu.h
--
2.56.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings 2026-10-25 19:18 [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support H. Nikolaus Schaller @ 2026-10-25 19:18 ` H. Nikolaus Schaller 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-25 19:18 ` [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support H. Nikolaus Schaller ` (2 subsequent siblings) 3 siblings, 2 replies; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-10-25 19:18 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, H. Nikolaus Schaller, Paul Boddie Add the device tree bindings and the clock ID definitions for the Clock Generation Unit (CGU) of the Ingenic X1600 SoC. The clock layout features specific I2S handling. To properly support the I2S controllers on the X1600 without relying on complex compound dividers that are not yet natively supported by the drivers, split the structures to explicitly describe the additional I2S divider fields. This design accounts for the current driver limitations regarding division encoding while matching the hardware's internal gating architecture. Furthermore, introduce dedicated I2S0 RX and TX clock definitions to allow independent and precise routing for I2S stream usage. Co-developed-by: Paul Boddie <paul@boddie.org.uk> Signed-off-by: Paul Boddie <paul@boddie.org.uk> Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- .../bindings/clock/ingenic,cgu.yaml | 2 + include/dt-bindings/clock/ingenic,x1600-cgu.h | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 include/dt-bindings/clock/ingenic,x1600-cgu.h diff --git a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml index 509df06b9c9d8..c622131c5c49b 100644 --- a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml +++ b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml @@ -28,6 +28,7 @@ select: - ingenic,jz4770-cgu - ingenic,jz4780-cgu - ingenic,x1000-cgu + - ingenic,x1600-cgu - ingenic,x1830-cgu required: - compatible @@ -58,6 +59,7 @@ properties: - ingenic,jz4770-cgu - ingenic,jz4780-cgu - ingenic,x1000-cgu + - ingenic,x1600-cgu - ingenic,x1830-cgu - const: simple-mfd minItems: 1 diff --git a/include/dt-bindings/clock/ingenic,x1600-cgu.h b/include/dt-bindings/clock/ingenic,x1600-cgu.h new file mode 100644 index 0000000000000..a0001a63a6b54 --- /dev/null +++ b/include/dt-bindings/clock/ingenic,x1600-cgu.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * This header provides clock numbers for the ingenic,x1600-cgu DT binding. + * + * They are roughly ordered as: + * - external clocks + * - PLLs + * - muxes/dividers in the order they appear in the x1600 programmers manual + * - gates in order of their bit in the CLKGR* registers + */ + +#ifndef __DT_BINDINGS_CLOCK_X1600_CGU_H__ +#define __DT_BINDINGS_CLOCK_X1600_CGU_H__ + +/* + * beware of unwritten rules: + * - list must start with 0 + * - list must not have "holes" + * - all clock parents must have lower number than a clock itself so that + * parents are initialized before + */ + +#define X1600_CLK_EXCLK 0 +#define X1600_CLK_RTCLK 1 +#define X1600_CLK_12M 2 +#define X1600_CLK_APLL 3 +#define X1600_CLK_EPLL 4 +#define X1600_CLK_MPLL 5 +#define X1600_CLK_SCLKA 6 +#define X1600_CLK_CPUMUX 7 +#define X1600_CLK_CPU 8 +#define X1600_CLK_L2CACHE 9 +#define X1600_CLK_AHB0 10 +#define X1600_CLK_AHB2PMUX 11 +#define X1600_CLK_AHB2 12 +#define X1600_CLK_PCLK 13 +#define X1600_CLK_DDR 14 +#define X1600_CLK_I2S0 15 +#define X1600_CLK_I2S1 16 +#define X1600_CLK_LCDPIXCLK 17 +#define X1600_CLK_MAC 18 +#define X1600_CLK_MSC0 19 +#define X1600_CLK_MSC1 20 +#define X1600_CLK_SSI0 21 +#define X1600_CLK_CIMMCLK 22 +#define X1600_CLK_EXCLK_DIV512 23 +#define X1600_CLK_RTC 24 +#define X1600_CLK_OTGPHY 25 +#define X1600_CLK_NEMC 26 +#define X1600_CLK_OTG0 27 +#define X1600_CLK_SMB0 28 +#define X1600_CLK_SMB1 29 +#define X1600_CLK_AIC 30 +#define X1600_CLK_SADC 31 +#define X1600_CLK_UART0 32 +#define X1600_CLK_UART1 33 +#define X1600_CLK_UART2 34 +#define X1600_CLK_UART3 35 +#define X1600_CLK_PDMA 36 +#define X1600_CLK_AES 37 +#define X1600_CLK_I2S0_RX 38 +#define X1600_CLK_I2S0_TX 39 + +#endif /* __DT_BINDINGS_CLOCK_X1600_CGU_H__ */ -- 2.56.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings 2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller @ 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-30 11:24 ` Krzysztof Kozlowski 1 sibling, 0 replies; 12+ messages in thread From: Krzysztof Kozlowski @ 2026-10-30 11:24 UTC (permalink / raw) To: H. Nikolaus Schaller Cc: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie On Sun, Oct 25, 2026 at 08:18:24PM +0100, H. Nikolaus Schaller wrote: > Add the device tree bindings and the clock ID definitions for the > Clock Generation Unit (CGU) of the Ingenic X1600 SoC. > > The clock layout features specific I2S handling. To properly support > the I2S controllers on the X1600 without relying on complex compound > dividers that are not yet natively supported by the drivers, split > the structures to explicitly describe the additional I2S divider > fields. This design accounts for the current driver limitations > regarding division encoding while matching the hardware's internal > gating architecture. > > Furthermore, introduce dedicated I2S0 RX and TX clock definitions to > allow independent and precise routing for I2S stream usage. > > Co-developed-by: Paul Boddie <paul@boddie.org.uk> > Signed-off-by: Paul Boddie <paul@boddie.org.uk> > Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > --- > .../bindings/clock/ingenic,cgu.yaml | 2 + > include/dt-bindings/clock/ingenic,x1600-cgu.h | 64 +++++++++++++++++++ > 2 files changed, 66 insertions(+) > create mode 100644 include/dt-bindings/clock/ingenic,x1600-cgu.h > > diff --git a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml > index 509df06b9c9d8..c622131c5c49b 100644 > --- a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml > +++ b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml > @@ -28,6 +28,7 @@ select: > - ingenic,jz4770-cgu > - ingenic,jz4780-cgu > - ingenic,x1000-cgu > + - ingenic,x1600-cgu > - ingenic,x1830-cgu > required: > - compatible > @@ -58,6 +59,7 @@ properties: > - ingenic,jz4770-cgu > - ingenic,jz4780-cgu > - ingenic,x1000-cgu > + - ingenic,x1600-cgu > - ingenic,x1830-cgu > - const: simple-mfd > minItems: 1 > diff --git a/include/dt-bindings/clock/ingenic,x1600-cgu.h b/include/dt-bindings/clock/ingenic,x1600-cgu.h > new file mode 100644 > index 0000000000000..a0001a63a6b54 > --- /dev/null > +++ b/include/dt-bindings/clock/ingenic,x1600-cgu.h > @@ -0,0 +1,64 @@ > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ > +/* > + * This header provides clock numbers for the ingenic,x1600-cgu DT binding. > + * > + * They are roughly ordered as: > + * - external clocks > + * - PLLs > + * - muxes/dividers in the order they appear in the x1600 programmers manual > + * - gates in order of their bit in the CLKGR* registers > + */ > + > +#ifndef __DT_BINDINGS_CLOCK_X1600_CGU_H__ > +#define __DT_BINDINGS_CLOCK_X1600_CGU_H__ > + > +/* > + * beware of unwritten rules: > + * - list must start with 0 > + * - list must not have "holes" Please drop this, no need for individual souces to document standard rules. If you think documentation misses them, then please update writing-bindings doc. If this is driver requirement, then please fix your driver not to impose such rules, although these two particularly are fine rules. > + * - all clock parents must have lower number than a clock itself so that > + * parents are initialized before > + */ Best regards, Krzysztof ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings 2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller 2026-10-30 11:24 ` Krzysztof Kozlowski @ 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-30 12:06 ` H. Nikolaus Schaller 1 sibling, 1 reply; 12+ messages in thread From: Krzysztof Kozlowski @ 2026-10-30 11:24 UTC (permalink / raw) To: H. Nikolaus Schaller Cc: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie On Sun, Oct 25, 2026 at 08:18:24PM +0100, H. Nikolaus Schaller wrote: > Add the device tree bindings and the clock ID definitions for the > Clock Generation Unit (CGU) of the Ingenic X1600 SoC. > > The clock layout features specific I2S handling. To properly support > the I2S controllers on the X1600 without relying on complex compound > dividers that are not yet natively supported by the drivers, split > the structures to explicitly describe the additional I2S divider > fields. This design accounts for the current driver limitations > regarding division encoding while matching the hardware's internal > gating architecture. > > Furthermore, introduce dedicated I2S0 RX and TX clock definitions to > allow independent and precise routing for I2S stream usage. > > Co-developed-by: Paul Boddie <paul@boddie.org.uk> > Signed-off-by: Paul Boddie <paul@boddie.org.uk> > Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > --- One more nit: A nit, subject: drop second/last, redundant "bindings". The "dt-bindings" prefix is already stating that these are bindings. See also: https://elixir.bootlin.com/linux/v7.1-rc7/source/Documentation/devicetree/bindings/submitting-patches.rst#L23 Best regards, Krzysztof ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings 2026-10-30 11:24 ` Krzysztof Kozlowski @ 2026-10-30 12:06 ` H. Nikolaus Schaller 0 siblings, 0 replies; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-10-30 12:06 UTC (permalink / raw) To: Krzysztof Kozlowski Cc: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie Hi Krzysztof, > Am 30.10.2026 um 12:24 schrieb Krzysztof Kozlowski <krzk@kernel.org>: > > On Sun, Oct 25, 2026 at 08:18:24PM +0100, H. Nikolaus Schaller wrote: >> Add the device tree bindings and the clock ID definitions for the >> Clock Generation Unit (CGU) of the Ingenic X1600 SoC. >> >> The clock layout features specific I2S handling. To properly support >> the I2S controllers on the X1600 without relying on complex compound >> dividers that are not yet natively supported by the drivers, split >> the structures to explicitly describe the additional I2S divider >> fields. This design accounts for the current driver limitations >> regarding division encoding while matching the hardware's internal >> gating architecture. >> >> Furthermore, introduce dedicated I2S0 RX and TX clock definitions to >> allow independent and precise routing for I2S stream usage. >> >> Co-developed-by: Paul Boddie <paul@boddie.org.uk> >> Signed-off-by: Paul Boddie <paul@boddie.org.uk> >> Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> >> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> >> --- > > One more nit: > > A nit, subject: drop second/last, redundant "bindings". The > "dt-bindings" prefix is already stating that these are bindings. > See also: > https://elixir.bootlin.com/linux/v7.1-rc7/source/Documentation/devicetree/bindings/submitting-patches.rst#L23 > thanks for both suggestions! A V2 is in preparation covering the previous and this comment and other aspects as well. BR nd thanks, Nikolaus ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support 2026-10-25 19:18 [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller @ 2026-10-25 19:18 ` H. Nikolaus Schaller 2026-10-26 10:16 ` kernel test robot 2026-11-11 21:43 ` Brian Masney 2026-10-25 19:18 ` [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 4/4] clk: ingenic: x1000-cgu: " H. Nikolaus Schaller 3 siblings, 2 replies; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-10-25 19:18 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie, H. Nikolaus Schaller From: Paul Boddie <paul@boddie.org.uk> Introduce clock driver support for the Clock Generation Unit (CGU) found in the Ingenic X1600 SoC. To support the X1600 platform, update the common Ingenic CGU core framework to accommodate a secondary post-VCO divider (OD1) within the PLL configuration registers. Additionally, prevent a NULL pointer dereference in the rate determination path by properly supplying the secondary divider tracking during PLL calculation calls. Implement custom handling for the I2S clocks on the X1600. Since complex compound hardware dividers are not yet natively supported by the core framework, explicit M-divider (mdiv) and N/D-divider (nddiv) structures are introduced to describe these specialized fields. This avoids a compilation failure and enables a stable, though limited, division encoding suitable for current needs. Furthermore, this patch: - Fixes the gating of the I2S0 and I2S1 clocks, matching the control bit behavior which functions as a clock enable flag. - Introduces the custom OTG PHY clock operations and initialisation routines utilizing the hardware's OPCR registers. - Registers the independent I2S0 RX and TX gate clocks employed by the X1600 peripheral block. Tested successfully on the LX16 (X1600) boards and CI20 (JZ4780) to not interefere. Checkpatch complains about not 4 lines of help paragraph but the style is the same as for the other machines. It also recommends using 'unsigned int' for the new struct ingenic_cgu_mdiv_info and struct ingenic_cgu_nddiv_info but this follows the style 'unsigned' of all other structs in cgu.h. Finally it complains about the empty line between struct ingenic_cgu_clk_info x1600_cgu_clocks[] = { and the comment. But I think it is more readable this way. Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> Co-developed-by: Paul Boddie <paul@boddie.org.uk> Signed-off-by: Paul Boddie <paul@boddie.org.uk> --- drivers/clk/ingenic/Kconfig | 10 + drivers/clk/ingenic/Makefile | 1 + drivers/clk/ingenic/cgu.c | 150 +++++++--- drivers/clk/ingenic/cgu.h | 42 ++- drivers/clk/ingenic/x1600-cgu.c | 476 ++++++++++++++++++++++++++++++++ 5 files changed, 646 insertions(+), 33 deletions(-) create mode 100644 drivers/clk/ingenic/x1600-cgu.c diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig index f80ac4f2992b4..9b8b00c9e6d13 100644 --- a/drivers/clk/ingenic/Kconfig +++ b/drivers/clk/ingenic/Kconfig @@ -75,6 +75,16 @@ config INGENIC_CGU_X1000 If building for a X1000 SoC, you want to say Y here. +config INGENIC_CGU_X1600 + bool "Ingenic X1600 CGU driver" + default MACH_X1600 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic X1600 + and compatible SoCs. + + If building for a X1600 SoC, you want to say Y here. + config INGENIC_CGU_X1830 bool "Ingenic X1830 CGU driver" default MACH_X1830 diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile index 81d8e23c26365..7e93e0893abe2 100644 --- a/drivers/clk/ingenic/Makefile +++ b/drivers/clk/ingenic/Makefile @@ -7,5 +7,6 @@ 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 +obj-$(CONFIG_INGENIC_CGU_X1600) += x1600-cgu.o obj-$(CONFIG_INGENIC_CGU_X1830) += x1830-cgu.o obj-$(CONFIG_INGENIC_TCU_CLK) += tcu.o diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 41e4c69131bd6..b4ef8ddf043a7 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -4,6 +4,7 @@ * * Copyright (c) 2013-2015 Imagination Technologies * Author: Paul Burton <paul.burton@mips.com> + * Copyright (c) 2023, 2024 Paul Boddie <paul@boddie.org.uk> */ #include <linux/bitops.h> @@ -76,6 +77,40 @@ ingenic_cgu_gate_set(struct ingenic_cgu *cgu, * PLL operations */ +static unsigned +ingenic_pll_recalc_rate_od(u32 ctl, u8 od_shift, u8 od_bits, u8 od_max, + const s8 *od_encoding) +{ + unsigned int od, od_enc = 0; + + if (od_bits > 0) { + od_enc = ctl >> od_shift; + od_enc &= GENMASK(od_bits - 1, 0); + } + + /* + * Use the encoding table if indicated. Otherwise, use the value + * directly, interpreting an encoded value of zero as a divider + * value of one. + */ + if (od_encoding) { + for (od = 0; od < od_max; od++) + if (od_encoding[od] == od_enc) + break; + od++; + } else { + od = od_enc ? od_enc : 1; + } + + /* if od_max = 0, od_bits should be 0 and od is fixed to 1. */ + if (od_max == 0) + WARN_ON_ONCE(od_bits != 0); + else + WARN_ON_ONCE(od == od_max); + + return od; +} + static unsigned long ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -83,7 +118,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); struct ingenic_cgu *cgu = ingenic_clk->cgu; const struct ingenic_cgu_pll_info *pll_info; - unsigned m, n, od, od_enc = 0; + unsigned int m, n, od, od1; bool bypass; u32 ctl; @@ -97,71 +132,82 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0); n += pll_info->n_offset; - if (pll_info->od_bits > 0) { - od_enc = ctl >> pll_info->od_shift; - od_enc &= GENMASK(pll_info->od_bits - 1, 0); - } - if (pll_info->bypass_bit >= 0) { - ctl = readl(cgu->base + pll_info->bypass_reg); + u32 ctl2 = readl(cgu->base + pll_info->bypass_reg); - bypass = !!(ctl & BIT(pll_info->bypass_bit)); + bypass = !!(ctl2 & BIT(pll_info->bypass_bit)); if (bypass) return parent_rate; } - for (od = 0; od < pll_info->od_max; od++) - if (pll_info->od_encoding[od] == od_enc) - break; + od = ingenic_pll_recalc_rate_od(ctl, pll_info->od_shift, pll_info->od_bits, + pll_info->od_max, pll_info->od_encoding); - /* if od_max = 0, od_bits should be 0 and od is fixed to 1. */ - if (pll_info->od_max == 0) - BUG_ON(pll_info->od_bits != 0); - else - BUG_ON(od == pll_info->od_max); - od++; + od1 = ingenic_pll_recalc_rate_od(ctl, pll_info->od1_shift, pll_info->od1_bits, + pll_info->od1_max, pll_info->od_encoding); return div_u64((u64)parent_rate * m * pll_info->rate_multiplier, - n * od); + n * od * od1); } 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) + unsigned int *pm, unsigned int *pn, unsigned int *pod, + unsigned int *pod1) { - unsigned int m, n, od = 1; + unsigned int m, n, od = 1, od1 = 1; /* - * The frequency after the input divider must be between 10 and 50 MHz. + * The frequency after the input divider must be within the range + * defined in the programming manual as FREF: + * + * JZ4740: 1 MHz - 15 MHz + * JZ4780: 183 kHz - 1.5 GHz + * X1000: 10 MHz - 50 MHz + * X1600: 1 MHz - 800 MHz + * X2000: 5 MHz - 200 MHz + * * The highest divider yields the best resolution. */ n = parent_rate / (10 * MHZ); 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); + /* + * The frequency after the VCO stage (parent * m / n) must be in the + * range defined in the programming manual as FVCO: + * + * JZ4740: 100 MHz - 500 MHz + * JZ4780: 300 MHz - 1.5 GHz + * X1000: 300 MHz - 600 MHz (low-band), 500 MHz - 1 GHz (high-band) + * X1600: 600 MHz - 2.4 GHz + * X2000: 2.4 GHz - 4.8 GHz + */ + m = (rate / MHZ) * od * od1 * n / (parent_rate / MHZ); 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; + *pod1 = od1; } 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) + unsigned int *pm, unsigned int *pn, unsigned int *pod, + unsigned int *pod1) { const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; - unsigned int m, n, od; + unsigned int m, n, od, od1 = 1; if (pll_info->calc_m_n_od) - (*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od); + (*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od, &od1); else - ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od); + ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od, &od1); if (pm) *pm = m; @@ -169,9 +215,11 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info, *pn = n; if (pod) *pod = od; + if (pod1) + *pod1 = od1; return div_u64((u64)parent_rate * m * pll_info->rate_multiplier, - n * od); + n * od * od1); } static int ingenic_pll_determine_rate(struct clk_hw *hw, @@ -181,7 +229,7 @@ static int ingenic_pll_determine_rate(struct clk_hw *hw, const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); req->rate = ingenic_pll_calc(clk_info, req->rate, req->best_parent_rate, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); return 0; } @@ -208,12 +256,12 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; unsigned long rate, flags; - unsigned int m, n, od; + unsigned int m, n, od, od1; int ret = 0; u32 ctl; rate = ingenic_pll_calc(clk_info, req_rate, parent_rate, - &m, &n, &od); + &m, &n, &od, &od1); if (rate != req_rate) pr_info("ingenic-cgu: request '%s' rate %luHz, actual %luHz\n", clk_info->name, req_rate, rate); @@ -229,7 +277,18 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, if (pll_info->od_bits > 0) { ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift); - ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; + if (pll_info->od_encoding) + ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; + else + ctl |= (od ? od : 1) << pll_info->od_shift; + } + + if (pll_info->od1_bits > 0) { + ctl &= ~(GENMASK(pll_info->od1_bits - 1, 0) << pll_info->od1_shift); + if (pll_info->od_encoding) + ctl |= pll_info->od_encoding[od1 - 1] << pll_info->od1_shift; + else + ctl |= (od1 ? od1 : 1) << pll_info->od1_shift; } writel(ctl, cgu->base + pll_info->reg); @@ -531,7 +590,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, struct ingenic_cgu *cgu = ingenic_clk->cgu; unsigned long rate, flags; unsigned int hw_div, div; - u32 reg, mask; + u32 reg, mask, d_reg; int ret = 0; if (clk_info->type & CGU_CLK_DIV) { @@ -554,6 +613,30 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, reg &= ~(mask << clk_info->div.shift); reg |= hw_div << clk_info->div.shift; + /* + * NOTE: Special treatment for the I2S dividers in the X1600. + * Set the multiplier to 1, imposing an N >= M*2 constraint, + * also setting D to "automatic" calculation. This permits the + * treatment of these dividers as normal dividers, although + * they are configured more similarly to PLLs. + */ + if (clk_info->mdiv.reg) { + if (div < 2) { + spin_unlock_irqrestore(&cgu->lock, flags); + return -EINVAL; + } + + mask = GENMASK(clk_info->mdiv.bits - 1, 0); + reg &= ~(mask << clk_info->mdiv.shift); + reg |= 1 << clk_info->mdiv.shift; + + if (clk_info->nddiv.reg) { + d_reg = readl(cgu->base + clk_info->nddiv.reg); + d_reg &= ~(1 << clk_info->nddiv.explicit_d_bit); + d_reg |= 1 << clk_info->nddiv.explicit_n_bit; + } + } + /* clear the stop bit */ if (clk_info->div.stop_bit != -1) reg &= ~BIT(clk_info->div.stop_bit); @@ -565,6 +648,9 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, /* update the hardware */ writel(reg, cgu->base + clk_info->div.reg); + if (clk_info->nddiv.reg) + writel(d_reg, cgu->base + clk_info->nddiv.reg); + /* wait for the change to take effect */ if (clk_info->div.busy_bit != -1) ret = ingenic_clk_check_stable(cgu, clk_info); diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index 0d417d69dab71..d5bdd7084b201 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -36,6 +36,12 @@ * @od_bits: the size of the post-VCO divider field in bits, or 0 if no * OD field exists (then the OD is fixed to 1) * @od_max: the maximum post-VCO divider value + * @od1_shift: the number of bits to shift the secondary post-VCO divider + * value by (ie. the index of the lowest bit of the post-VCO + * divider value in the PLL's control register) + * @od1_bits: the size of the secondary post-VCO divider field in bits, or 0 + * if no OD1 field exists (then the OD1 is fixed to 1) + * @od1_max: the maximum secondary post-VCO divider value * @od_encoding: a pointer to an array mapping post-VCO divider values to * their encoded values in the PLL control register, or -1 for * unsupported values @@ -56,13 +62,15 @@ struct ingenic_cgu_pll_info { u8 m_shift, m_bits, m_offset; u8 n_shift, n_bits, n_offset; u8 od_shift, od_bits, od_max; + u8 od1_shift, od1_bits, od1_max; unsigned bypass_reg; s8 bypass_bit; s8 enable_bit; s8 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); + unsigned int *m, unsigned int *n, unsigned int *od, + unsigned int *od1); void (*set_rate_hook)(const struct ingenic_cgu_pll_info *pll_info, unsigned long rate, unsigned long parent_rate); }; @@ -109,6 +117,36 @@ struct ingenic_cgu_div_info { const u8 *div_table; }; +/** + * struct ingenic_cgu_mdiv_info - information about a divider M parameter + * @reg: offset of the divider control register within the CGU + * @shift: number of bits to left shift the M divide value by (ie. the index + * of the lowest bit of the divide value within its control + * register) + * @div: number to divide the M divider value by (i.e. if the + * effective divider value is the value written to the register + * multiplied by some constant) + * @bits: the size of the M divide value in bits + */ +struct ingenic_cgu_mdiv_info { + unsigned reg; + u8 shift; + u8 div; + u8 bits; +}; + +/** + * struct ingenic_cgu_nddiv_info - information about divider N and D parameters + * @reg: offset of the D divider control register within the CGU + * @explicit_n_bit: the bit providing the explicit N divider flag + * @explicit_d_bit: the bit providing the explicit D divider flag + */ +struct ingenic_cgu_nddiv_info { + unsigned reg; + u8 explicit_n_bit; + u8 explicit_d_bit; +}; + /** * struct ingenic_cgu_fixdiv_info - information about a fixed divider * @div: the divider applied to the parent clock @@ -180,6 +218,8 @@ struct ingenic_cgu_clk_info { struct ingenic_cgu_gate_info gate; struct ingenic_cgu_mux_info mux; struct ingenic_cgu_div_info div; + struct ingenic_cgu_mdiv_info mdiv; + struct ingenic_cgu_nddiv_info nddiv; struct ingenic_cgu_fixdiv_info fixdiv; }; diff --git a/drivers/clk/ingenic/x1600-cgu.c b/drivers/clk/ingenic/x1600-cgu.c new file mode 100644 index 0000000000000..627203f5cabe8 --- /dev/null +++ b/drivers/clk/ingenic/x1600-cgu.c @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Ingenic X1600 SoC CGU driver + * + * Copyright (c) 2013-2015 Imagination Technologies + * Author: Paul Burton <paul.burton@mips.com> + * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> + * Copyright (c) 2023, 2024 Paul Boddie <paul@boddie.org.uk> + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/rational.h> +#include <linux/of.h> + +#include <dt-bindings/clock/ingenic,x1600-cgu.h> + +#include "cgu.h" +#include "pm.h" + +/* CGU register offsets */ +#define CGU_REG_CLOCKCONTROL 0x00 +#define CGU_REG_LCR 0x04 +#define CGU_REG_APLL 0x10 +#define CGU_REG_MPLL 0x14 +#define CGU_REG_EPLL 0x18 +#define CGU_REG_CLKGR0 0x20 +#define CGU_REG_OPCR 0x24 +#define CGU_REG_CLKGR1 0x28 +#define CGU_REG_DDRCDR 0x2c +#define CGU_REG_CPSPR 0x34 +#define CGU_REG_CPSPPR 0x38 +#define CGU_REG_USBPCR 0x3c +#define CGU_REG_USBRDT 0x40 +#define CGU_REG_USBVBFIL 0x44 +#define CGU_REG_USBPCR1 0x48 +#define CGU_REG_MACCDR 0x54 +#define CGU_REG_SSICDR 0x5c +#define CGU_REG_I2S0CDR 0x60 +#define CGU_REG_LPCDR 0x64 +#define CGU_REG_MSC0CDR 0x68 +#define CGU_REG_PWMCDR 0x6c +#define CGU_REG_I2S0CDR1 0x70 +#define CGU_REG_SFCCDR 0x74 +#define CGU_REG_CIMCDR 0x78 +#define CGU_REG_I2S1CDR 0x7c +#define CGU_REG_I2S1CDR1 0x80 +#define CGU_REG_APLLFRAC 0x84 +#define CGU_REG_MPLLFRAC 0x88 +#define CGU_REG_EPLLFRAC 0x8c +#define CGU_REG_CAN0CDR 0xa0 +#define CGU_REG_MSC1CDR 0xa4 +#define CGU_REG_CAN1CDR 0xa8 +#define CGU_REG_CDBUSCDR 0xac +#define CGU_REG_CMP_INTR 0xb0 +#define CGU_REG_CMP_INTRE 0xb4 +#define CGU_REG_CMP_SFTINT 0xbc +#define CGU_REG_DRCG 0xd0 +#define CGU_REG_CLOCKSTATUS 0xd4 +#define CGU_REG_MPHY0C 0xe4 + +/* bits within the OPCR register */ +#define OPCR_SPENDN0 BIT(7) +#define OPCR_GATEUSBPHYCLK BIT(23) + +static struct ingenic_cgu *cgu; + +static int x1600_otg_phy_enable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel((readl(reg_opcr) & ~OPCR_GATEUSBPHYCLK) | OPCR_SPENDN0, reg_opcr); + + return 0; +} + +static void x1600_otg_phy_disable(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + writel((readl(reg_opcr) & ~OPCR_SPENDN0) | OPCR_GATEUSBPHYCLK, reg_opcr); +} + +static int x1600_otg_phy_is_enabled(struct clk_hw *hw) +{ + void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; + + return (readl(reg_opcr) & (OPCR_SPENDN0 | OPCR_GATEUSBPHYCLK)) == OPCR_SPENDN0; +} + +static u8 x1600_otg_phy_get_parent(struct clk_hw * __maybe_unused hw) +{ + return 0; +} + +static const struct clk_ops x1600_otg_phy_ops = { + .enable = x1600_otg_phy_enable, + .disable = x1600_otg_phy_disable, + .is_enabled = x1600_otg_phy_is_enabled, + .get_parent = x1600_otg_phy_get_parent, +}; + +static void +x1600_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, + unsigned int *pod1) +{ + const unsigned int od_max = pll_info->od_max - 1; + const unsigned int od1_max = pll_info->od1_max - 1; + const unsigned int m_max = GENMASK(pll_info->m_bits - 1, 0); + const unsigned int n_max = GENMASK(pll_info->n_bits - 1, 0); + unsigned long m, n; + unsigned int od = 1, od1 = 1; + const unsigned long fvco_min = 600000000, fvco_max = 2400000000; + unsigned long fvco; + + /* + * Combined output divider range: + * + * ceil(fvco_min / rate) - fvco_max / rate + */ + unsigned int od_combined_min = (fvco_min + rate) / rate; + unsigned int od_combined_max = fvco_max / rate; + unsigned int od_combined; + + for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { + od = int_sqrt(od_combined); + od1 = od_combined / od; + + /* od == floor(sqrt(od_combined)); od1 >= od */ + if ((od * od1 == od_combined) && od <= od_max && od1 <= od1_max) { + fvco = rate * od_combined; + rational_best_approximation(fvco, parent_rate, m_max, n_max, &m, &n); + break; + } + } + + *pm = m; + *pn = n; + *pod = od; + *pod1 = od1; +} + +static const struct ingenic_cgu_clk_info x1600_cgu_clocks[] = { + + /* External clocks */ + + [X1600_CLK_EXCLK] = { "ext", CGU_CLK_EXT }, + [X1600_CLK_RTCLK] = { "rtc", CGU_CLK_EXT }, + [X1600_CLK_12M] = { "clk12m", CGU_CLK_EXT }, + + /* PLLs */ + +#define DEF_PLL(name) { \ + .reg = CGU_REG_ ## name, \ + .rate_multiplier = 1, \ + .m_shift = 20, \ + .m_bits = 12, \ + .m_offset = 0, \ + .n_shift = 14, \ + .n_bits = 6, \ + .n_offset = 0, \ + .od_shift = 8, \ + .od_bits = 3, \ + .od_max = 8, \ + .od1_shift = 11, \ + .od1_bits = 3, \ + .od1_max = 8, \ + .od_encoding = 0, \ + .stable_bit = 2, \ + .enable_bit = 0, \ + .bypass_bit = -1, \ + .calc_m_n_od = x1600_pll_calc_m_n_od, \ +} + + [X1600_CLK_APLL] = { + "apll", CGU_CLK_PLL, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .pll = DEF_PLL(APLL), + }, + + [X1600_CLK_MPLL] = { + "mpll", CGU_CLK_PLL, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .pll = DEF_PLL(MPLL), + }, + + [X1600_CLK_EPLL] = { + "epll", CGU_CLK_PLL, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .pll = DEF_PLL(EPLL), + }, + +#undef DEF_PLL + + /* Muxes & dividers */ + + [X1600_CLK_SCLKA] = { + "sclk_a", CGU_CLK_MUX, + .parents = { -1, X1600_CLK_EXCLK, X1600_CLK_APLL, -1 }, + .mux = { CGU_REG_CLOCKCONTROL, 30, 2 }, + }, + + [X1600_CLK_CPUMUX] = { + "cpumux", CGU_CLK_MUX, + .parents = { -1, X1600_CLK_SCLKA, X1600_CLK_MPLL, -1 }, + .mux = { CGU_REG_CLOCKCONTROL, 28, 2 }, + }, + + [X1600_CLK_CPU] = { + "cpu", CGU_CLK_DIV, + /* + * Disabling the CPU clock or any parent clocks will hang the + * system; mark it critical. + */ + .flags = CLK_IS_CRITICAL, + .parents = { X1600_CLK_CPUMUX, -1, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 0, 1, 4, 22, -1, -1 }, + }, + + [X1600_CLK_L2CACHE] = { + "l2cache", CGU_CLK_DIV, + /* + * The L2 cache clock is critical if caches are enabled and + * disabling it or any parent clocks will hang the system. + */ + .flags = CLK_IS_CRITICAL, + .parents = { X1600_CLK_CPUMUX, -1, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 4, 1, 4, -1, -1, -1 }, + }, + + [X1600_CLK_AHB0] = { + "ahb0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { -1, X1600_CLK_SCLKA, X1600_CLK_MPLL, -1 }, + .mux = { CGU_REG_CLOCKCONTROL, 26, 2 }, + .div = { CGU_REG_CLOCKCONTROL, 8, 1, 4, 21, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 29 }, + }, + + [X1600_CLK_AHB2PMUX] = { + "ahb2_apb_mux", CGU_CLK_MUX, + .parents = { -1, X1600_CLK_SCLKA, X1600_CLK_MPLL, -1 }, + .mux = { CGU_REG_CLOCKCONTROL, 24, 2 }, + }, + + [X1600_CLK_AHB2] = { + "ahb2", CGU_CLK_DIV, + .parents = { X1600_CLK_AHB2PMUX, -1, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 12, 1, 4, 20, -1, -1 }, + }, + + [X1600_CLK_PCLK] = { + "pclk", CGU_CLK_DIV, + .parents = { X1600_CLK_AHB2PMUX, -1, -1, -1 }, + .div = { CGU_REG_CLOCKCONTROL, 16, 1, 4, 20, -1, -1 }, + }, + + [X1600_CLK_DDR] = { + "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + /* + * Disabling DDR clock or its parents will render DRAM + * inaccessible; mark it critical. + */ + .flags = CLK_IS_CRITICAL, + .parents = { -1, X1600_CLK_SCLKA, X1600_CLK_MPLL, -1 }, + .mux = { CGU_REG_DDRCDR, 30, 2 }, + .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 31 }, + }, + + [X1600_CLK_I2S0] = { + "i2s0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_EPLL, -1, -1 }, + .mux = { CGU_REG_I2S0CDR, 30, 1 }, + .div = { CGU_REG_I2S0CDR, 20, 1, 9, -1, -1, -1 }, + .mdiv = { CGU_REG_I2S0CDR, 0, 1, 20 }, + .nddiv = { CGU_REG_I2S0CDR1, 31, 30 }, + .gate = { CGU_REG_I2S0CDR, 29, true }, + }, + + [X1600_CLK_I2S1] = { + "i2s1", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_EPLL, -1, -1 }, + .mux = { CGU_REG_I2S1CDR, 30, 1 }, + .div = { CGU_REG_I2S1CDR, 20, 1, 9, -1, -1, -1 }, + .mdiv = { CGU_REG_I2S1CDR, 0, 1, 20 }, + .nddiv = { CGU_REG_I2S1CDR1, 31, 30 }, + .gate = { CGU_REG_I2S1CDR, 29, true }, + }, + + [X1600_CLK_LCDPIXCLK] = { + "lcd0pixclk", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_LPCDR, 30, 2 }, + .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 }, + .gate = { CGU_REG_CLKGR0, 23 }, + }, + + [X1600_CLK_MAC] = { + "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_MACCDR, 30, 2 }, + .div = { CGU_REG_MACCDR, 0, 1, 8, 28, 27, 26 }, + .gate = { CGU_REG_CLKGR1, 23 }, + }, + + [X1600_CLK_MSC0] = { + "msc0", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_MSC0CDR, 30, 2 }, + .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 4 }, + }, + + [X1600_CLK_MSC1] = { + "msc1", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_MSC1CDR, 30, 2 }, + .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 5 }, + }, + + [X1600_CLK_SSI0] = { + "ssi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_SSICDR, 30, 2 }, + .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 }, + .gate = { CGU_REG_CLKGR0, 19 }, + }, + + [X1600_CLK_CIMMCLK] = { + "cim_mclk", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { X1600_CLK_SCLKA, X1600_CLK_MPLL, + X1600_CLK_EPLL, -1 }, + .mux = { CGU_REG_CIMCDR, 30, 2 }, + .div = { CGU_REG_CIMCDR, 0, 1, 8, 30, 29, 28 }, + .gate = { CGU_REG_CLKGR0, 22 }, + }, + + [X1600_CLK_EXCLK_DIV512] = { + "exclk_div512", CGU_CLK_FIXDIV, + .parents = { X1600_CLK_EXCLK }, + .fixdiv = { 512 }, + }, + + [X1600_CLK_RTC] = { + "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK_DIV512, X1600_CLK_RTCLK }, + .mux = { CGU_REG_OPCR, 2, 1}, + }, + + /* Custom (SoC-specific) OTG PHY */ + + [X1600_CLK_OTGPHY] = { + "otg_phy", CGU_CLK_CUSTOM, + .parents = { X1600_CLK_12M }, + .custom = { &x1600_otg_phy_ops }, + }, + + /* Gate-only clocks */ + + [X1600_CLK_NEMC] = { + "nemc", CGU_CLK_GATE, + .parents = { X1600_CLK_AHB2, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 0 }, + }, + + [X1600_CLK_OTG0] = { + "otg0", CGU_CLK_GATE, + .parents = { X1600_CLK_AHB2, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 3 }, + }, + + [X1600_CLK_SMB0] = { + "smb0", CGU_CLK_GATE, + .parents = { X1600_CLK_PCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 7 }, + }, + + [X1600_CLK_SMB1] = { + "smb1", CGU_CLK_GATE, + .parents = { X1600_CLK_PCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 8 }, + }, + + [X1600_CLK_AIC] = { + "aic", CGU_CLK_GATE, + .parents = { X1600_CLK_AHB2, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 11 }, + }, + + [X1600_CLK_I2S0_RX] = { + "i2s0_rx", CGU_CLK_GATE, + .parents = { X1600_CLK_I2S0, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 8 }, + }, + + [X1600_CLK_I2S0_TX] = { + "i2s0_tx", CGU_CLK_GATE, + .parents = { X1600_CLK_I2S1, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 9 }, + }, + + [X1600_CLK_SADC] = { + "sadc", CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 14 }, + }, + + [X1600_CLK_UART0] = { + "uart0", CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 14 }, + }, + + [X1600_CLK_UART1] = { + "uart1", CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 15 }, + }, + + [X1600_CLK_UART2] = { + "uart2", CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 16 }, + }, + + [X1600_CLK_UART3] = { + "uart3", CGU_CLK_GATE, + .parents = { X1600_CLK_EXCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 16 }, + }, + + [X1600_CLK_PDMA] = { + "pdma", CGU_CLK_GATE, + .parents = { X1600_CLK_AHB2, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR0, 21 }, + }, + + [X1600_CLK_AES] = { + "aes", CGU_CLK_GATE, + .parents = { X1600_CLK_AHB2, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR1, 24 }, + }, + +}; + +static void __init x1600_cgu_init(struct device_node *np) +{ + int retval; + + cgu = ingenic_cgu_new(x1600_cgu_clocks, + ARRAY_SIZE(x1600_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__); + return; + } + + ingenic_cgu_register_syscore(cgu); +} + +CLK_OF_DECLARE_DRIVER(x1600_cgu, "ingenic,x1600-cgu", x1600_cgu_init); -- 2.56.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support 2026-10-25 19:18 ` [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support H. Nikolaus Schaller @ 2026-10-26 10:16 ` kernel test robot 2026-11-11 21:43 ` Brian Masney 1 sibling, 0 replies; 12+ messages in thread From: kernel test robot @ 2026-10-26 10:16 UTC (permalink / raw) To: H. Nikolaus Schaller, Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil Cc: llvm, oe-kbuild-all, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie, H. Nikolaus Schaller Hi Nikolaus, kernel test robot noticed the following build warnings: [auto build test WARNING on clk/clk-next] [also build test WARNING on robh/for-next linus/master v7.3 next-20261023] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/H-Nikolaus-Schaller/dt-bindings-clock-Add-Ingenic-X1600-CGU-bindings/20261025-201824 base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next patch link: https://lore.kernel.org/r/50983be55e467076e83e3ffc37b30fc4e5648e15.1792955907.git.hns%40goldelico.com patch subject: [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20261026/202610261821.QhaEUvEU-lkp@intel.com/config) compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project 186e70f4e6a1521991d2340d3d49b23b1beff11f) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261026/202610261821.QhaEUvEU-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202610261821.QhaEUvEU-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/clk/ingenic/x1600-cgu.c:129:38: warning: variable 'm' is used uninitialized whenever 'for' loop exits because its condition is false [-Wsometimes-uninitialized] 129 | for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/clk/ingenic/x1600-cgu.c:141:8: note: uninitialized use occurs here 141 | *pm = m; | ^ drivers/clk/ingenic/x1600-cgu.c:129:38: note: remove the condition if it is always true 129 | for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/clk/ingenic/x1600-cgu.c:115:17: note: initialize the variable 'm' to silence this warning 115 | unsigned long m, n; | ^ | = 0 >> drivers/clk/ingenic/x1600-cgu.c:129:38: warning: variable 'n' is used uninitialized whenever 'for' loop exits because its condition is false [-Wsometimes-uninitialized] 129 | for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/clk/ingenic/x1600-cgu.c:142:8: note: uninitialized use occurs here 142 | *pn = n; | ^ drivers/clk/ingenic/x1600-cgu.c:129:38: note: remove the condition if it is always true 129 | for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/clk/ingenic/x1600-cgu.c:115:20: note: initialize the variable 'n' to silence this warning 115 | unsigned long m, n; | ^ | = 0 2 warnings generated. vim +129 drivers/clk/ingenic/x1600-cgu.c 104 105 static void 106 x1600_pll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, 107 unsigned long rate, unsigned long parent_rate, 108 unsigned int *pm, unsigned int *pn, unsigned int *pod, 109 unsigned int *pod1) 110 { 111 const unsigned int od_max = pll_info->od_max - 1; 112 const unsigned int od1_max = pll_info->od1_max - 1; 113 const unsigned int m_max = GENMASK(pll_info->m_bits - 1, 0); 114 const unsigned int n_max = GENMASK(pll_info->n_bits - 1, 0); 115 unsigned long m, n; 116 unsigned int od = 1, od1 = 1; 117 const unsigned long fvco_min = 600000000, fvco_max = 2400000000; 118 unsigned long fvco; 119 120 /* 121 * Combined output divider range: 122 * 123 * ceil(fvco_min / rate) - fvco_max / rate 124 */ 125 unsigned int od_combined_min = (fvco_min + rate) / rate; 126 unsigned int od_combined_max = fvco_max / rate; 127 unsigned int od_combined; 128 > 129 for (od_combined = od_combined_min; od_combined <= od_combined_max; od_combined++) { 130 od = int_sqrt(od_combined); 131 od1 = od_combined / od; 132 133 /* od == floor(sqrt(od_combined)); od1 >= od */ 134 if ((od * od1 == od_combined) && od <= od_max && od1 <= od1_max) { 135 fvco = rate * od_combined; 136 rational_best_approximation(fvco, parent_rate, m_max, n_max, &m, &n); 137 break; 138 } 139 } 140 141 *pm = m; 142 *pn = n; 143 *pod = od; 144 *pod1 = od1; 145 } 146 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support 2026-10-25 19:18 ` [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support H. Nikolaus Schaller 2026-10-26 10:16 ` kernel test robot @ 2026-11-11 21:43 ` Brian Masney 2026-11-11 21:51 ` H. Nikolaus Schaller 1 sibling, 1 reply; 12+ messages in thread From: Brian Masney @ 2026-11-11 21:43 UTC (permalink / raw) To: H. Nikolaus Schaller Cc: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie, Brian Masney > Introduce clock driver support for the Clock Generation Unit (CGU) > found in the Ingenic X1600 SoC. > > To support the X1600 platform, update the common Ingenic CGU core > framework to accommodate a secondary post-VCO divider (OD1) within > the PLL configuration registers. Additionally, prevent a NULL pointer > dereference in the rate determination path by properly supplying the > secondary divider tracking during PLL calculation calls. > > Implement custom handling for the I2S clocks on the X1600. Since > complex compound hardware dividers are not yet natively supported by the > core framework, explicit M-divider (mdiv) and N/D-divider (nddiv) > structures are introduced to describe these specialized fields. This > avoids a compilation failure and enables a stable, though limited, > division encoding suitable for current needs. > > Furthermore, this patch: > - Fixes the gating of the I2S0 and I2S1 clocks, matching the control > bit behavior which functions as a clock enable flag. > - Introduces the custom OTG PHY clock operations and initialisation > routines utilizing the hardware's OPCR registers. > - Registers the independent I2S0 RX and TX gate clocks employed by the > X1600 peripheral block. Just from reading the commit message this patch needs to be split up further into several smaller patches to make it easier to review. Ideally try to make the different bullet points separate patches. > Tested successfully on the LX16 (X1600) boards and CI20 (JZ4780) to > not interefere. > > Checkpatch complains about not 4 lines of help paragraph but the > style is the same as for the other machines. It also recommends > using 'unsigned int' for the new struct ingenic_cgu_mdiv_info > and struct ingenic_cgu_nddiv_info but this follows the style 'unsigned' > of all other structs in cgu.h. Finally it complains about the empty > line between struct ingenic_cgu_clk_info x1600_cgu_clocks[] = { > and the comment. But I think it is more readable this way. The checkpatch note can go below the --- below. > > Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > Co-developed-by: Paul Boddie <paul@boddie.org.uk> > Signed-off-by: Paul Boddie <paul@boddie.org.uk> > --- > drivers/clk/ingenic/Kconfig | 10 + > drivers/clk/ingenic/Makefile | 1 + > drivers/clk/ingenic/cgu.c | 150 +++++++--- > drivers/clk/ingenic/cgu.h | 42 ++- > drivers/clk/ingenic/x1600-cgu.c | 476 ++++++++++++++++++++++++++++++++ > 5 files changed, 646 insertions(+), 33 deletions(-) > create mode 100644 drivers/clk/ingenic/x1600-cgu.c > > diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig > index f80ac4f2992b..9b8b00c9e6d1 100644 > --- a/drivers/clk/ingenic/Kconfig > +++ b/drivers/clk/ingenic/Kconfig > @@ -75,6 +75,16 @@ config INGENIC_CGU_X1000 > > If building for a X1000 SoC, you want to say Y here. > > +config INGENIC_CGU_X1600 > + bool "Ingenic X1600 CGU driver" > + default MACH_X1600 > + select INGENIC_CGU_COMMON > + help > + Support the clocks provided by the CGU hardware on Ingenic X1600 > + and compatible SoCs. > + > + If building for a X1600 SoC, you want to say Y here. > + > config INGENIC_CGU_X1830 > bool "Ingenic X1830 CGU driver" > default MACH_X1830 > diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile > index 81d8e23c2636..7e93e0893abe 100644 > --- a/drivers/clk/ingenic/Makefile > +++ b/drivers/clk/ingenic/Makefile > @@ -7,5 +7,6 @@ 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 > +obj-$(CONFIG_INGENIC_CGU_X1600) += x1600-cgu.o > obj-$(CONFIG_INGENIC_CGU_X1830) += x1830-cgu.o > obj-$(CONFIG_INGENIC_TCU_CLK) += tcu.o > diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c > index ad223aa20e8d..c4fbee32c3b9 100644 > --- a/drivers/clk/ingenic/cgu.c > +++ b/drivers/clk/ingenic/cgu.c > @@ -4,6 +4,7 @@ > * > * Copyright (c) 2013-2015 Imagination Technologies > * Author: Paul Burton <paul.burton@mips.com> > + * Copyright (c) 2023, 2024 Paul Boddie <paul@boddie.org.uk> > */ > > #include <linux/bitops.h> > @@ -76,6 +77,40 @@ ingenic_cgu_gate_set(struct ingenic_cgu *cgu, > * PLL operations > */ > > +static unsigned > +ingenic_pll_recalc_rate_od(u32 ctl, u8 od_shift, u8 od_bits, u8 od_max, > + const s8 *od_encoding) > +{ > + unsigned int od, od_enc = 0; > + > + if (od_bits > 0) { > + od_enc = ctl >> od_shift; > + od_enc &= GENMASK(od_bits - 1, 0); > + } > + > + /* > + * Use the encoding table if indicated. Otherwise, use the value > + * directly, interpreting an encoded value of zero as a divider > + * value of one. > + */ > + if (od_encoding) { > + for (od = 0; od < od_max; od++) > + if (od_encoding[od] == od_enc) > + break; > + od++; So if the entry is not found, then od will be set to od_max + 1, and it will pass through the warning checks. I started to look through the rest of the driver but I stopped because there's just too many unrelated changes here. This needs to be split up further into separate patches to make it easier to review. If your commit message has the word 'and' then that's a hint that you may want to consider splitting it up further. Also be sure to go through all of the feedback from Sashiko. Brian -- Brian Masney <masneyb@kernel.org> ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support 2026-11-11 21:43 ` Brian Masney @ 2026-11-11 21:51 ` H. Nikolaus Schaller 0 siblings, 0 replies; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-11-11 21:51 UTC (permalink / raw) To: Brian Masney Cc: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil, linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, Paul Boddie Hi Brian, > Am 11.11.2026 um 22:43 schrieb Brian Masney <masneyb@kernel.org>: > >> Introduce clock driver support for the Clock Generation Unit (CGU) >> found in the Ingenic X1600 SoC. >> >> To support the X1600 platform, update the common Ingenic CGU core >> framework to accommodate a secondary post-VCO divider (OD1) within >> the PLL configuration registers. Additionally, prevent a NULL pointer >> dereference in the rate determination path by properly supplying the >> secondary divider tracking during PLL calculation calls. >> >> Implement custom handling for the I2S clocks on the X1600. Since >> complex compound hardware dividers are not yet natively supported by the >> core framework, explicit M-divider (mdiv) and N/D-divider (nddiv) >> structures are introduced to describe these specialized fields. This >> avoids a compilation failure and enables a stable, though limited, >> division encoding suitable for current needs. >> >> Furthermore, this patch: >> - Fixes the gating of the I2S0 and I2S1 clocks, matching the control >> bit behavior which functions as a clock enable flag. >> - Introduces the custom OTG PHY clock operations and initialisation >> routines utilizing the hardware's OPCR registers. >> - Registers the independent I2S0 RX and TX gate clocks employed by the >> X1600 peripheral block. > > Just from reading the commit message this patch needs to be split up > further into several smaller patches to make it easier to review. > Ideally try to make the different bullet points separate patches. Yes, that is already in preparation for a V2. We will also extend this to cover the X2000 and X2600 (and JZ4730). This needs to extend the core first and then add bindings and CGU code tables one after the other. > >> Tested successfully on the LX16 (X1600) boards and CI20 (JZ4780) to >> not interefere. >> >> Checkpatch complains about not 4 lines of help paragraph but the >> style is the same as for the other machines. It also recommends >> using 'unsigned int' for the new struct ingenic_cgu_mdiv_info >> and struct ingenic_cgu_nddiv_info but this follows the style 'unsigned' >> of all other structs in cgu.h. Finally it complains about the empty >> line between struct ingenic_cgu_clk_info x1600_cgu_clocks[] = { >> and the comment. But I think it is more readable this way. > > The checkpatch note can go below the --- below. Fine. > >> >> Co-developed-by: H. Nikolaus Schaller <hns@goldelico.com> >> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> >> Co-developed-by: Paul Boddie <paul@boddie.org.uk> >> Signed-off-by: Paul Boddie <paul@boddie.org.uk> >> --- >> drivers/clk/ingenic/Kconfig | 10 + >> drivers/clk/ingenic/Makefile | 1 + >> drivers/clk/ingenic/cgu.c | 150 +++++++--- >> drivers/clk/ingenic/cgu.h | 42 ++- >> drivers/clk/ingenic/x1600-cgu.c | 476 ++++++++++++++++++++++++++++++++ >> 5 files changed, 646 insertions(+), 33 deletions(-) >> create mode 100644 drivers/clk/ingenic/x1600-cgu.c >> >> diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig >> index f80ac4f2992b..9b8b00c9e6d1 100644 >> --- a/drivers/clk/ingenic/Kconfig >> +++ b/drivers/clk/ingenic/Kconfig >> @@ -75,6 +75,16 @@ config INGENIC_CGU_X1000 >> >> If building for a X1000 SoC, you want to say Y here. >> >> +config INGENIC_CGU_X1600 >> + bool "Ingenic X1600 CGU driver" >> + default MACH_X1600 >> + select INGENIC_CGU_COMMON >> + help >> + Support the clocks provided by the CGU hardware on Ingenic X1600 >> + and compatible SoCs. >> + >> + If building for a X1600 SoC, you want to say Y here. >> + >> config INGENIC_CGU_X1830 >> bool "Ingenic X1830 CGU driver" >> default MACH_X1830 >> diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile >> index 81d8e23c2636..7e93e0893abe 100644 >> --- a/drivers/clk/ingenic/Makefile >> +++ b/drivers/clk/ingenic/Makefile >> @@ -7,5 +7,6 @@ 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 >> +obj-$(CONFIG_INGENIC_CGU_X1600) += x1600-cgu.o >> obj-$(CONFIG_INGENIC_CGU_X1830) += x1830-cgu.o >> obj-$(CONFIG_INGENIC_TCU_CLK) += tcu.o >> diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c >> index ad223aa20e8d..c4fbee32c3b9 100644 >> --- a/drivers/clk/ingenic/cgu.c >> +++ b/drivers/clk/ingenic/cgu.c >> @@ -4,6 +4,7 @@ >> * >> * Copyright (c) 2013-2015 Imagination Technologies >> * Author: Paul Burton <paul.burton@mips.com> >> + * Copyright (c) 2023, 2024 Paul Boddie <paul@boddie.org.uk> >> */ >> >> #include <linux/bitops.h> >> @@ -76,6 +77,40 @@ ingenic_cgu_gate_set(struct ingenic_cgu *cgu, >> * PLL operations >> */ >> >> +static unsigned >> +ingenic_pll_recalc_rate_od(u32 ctl, u8 od_shift, u8 od_bits, u8 od_max, >> + const s8 *od_encoding) >> +{ >> + unsigned int od, od_enc = 0; >> + >> + if (od_bits > 0) { >> + od_enc = ctl >> od_shift; >> + od_enc &= GENMASK(od_bits - 1, 0); >> + } >> + >> + /* >> + * Use the encoding table if indicated. Otherwise, use the value >> + * directly, interpreting an encoded value of zero as a divider >> + * value of one. >> + */ >> + if (od_encoding) { >> + for (od = 0; od < od_max; od++) >> + if (od_encoding[od] == od_enc) >> + break; >> + od++; > > So if the entry is not found, then od will be set to od_max + 1, and it > will pass through the warning checks. Sashiko also commented on such issues. > > I started to look through the rest of the driver but I stopped because > there's just too many unrelated changes here. This needs to be split up > further into separate patches to make it easier to review. If your > commit message has the word 'and' then that's a hint that you may want > to consider splitting it up further. > > Also be sure to go through all of the feedback from Sashiko. Yes, sure. BR and thanks, Nikolaus ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes 2026-10-25 19:18 [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support H. Nikolaus Schaller @ 2026-10-25 19:18 ` H. Nikolaus Schaller 2026-10-25 22:54 ` Paul Cercueil 2026-10-25 19:18 ` [PATCH 4/4] clk: ingenic: x1000-cgu: " H. Nikolaus Schaller 3 siblings, 1 reply; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-10-25 19:18 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, H. Nikolaus Schaller The common Ingenic CGU core framework was updated to support a secondary post-VCO divider (OD1), which extended the signature of the calc_m_n_od() callback. Update the JZ4760 CGU driver implementation to accept the new pod1 argument, preventing compilation errors. The parameter remains unused on this specific SoC architecture. Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- drivers/clk/ingenic/jz4760-cgu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c index 372fe4b079927..52cc5ce150048 100644 --- a/drivers/clk/ingenic/jz4760-cgu.c +++ b/drivers/clk/ingenic/jz4760-cgu.c @@ -56,7 +56,8 @@ static const u8 jz4760_cgu_pll_half_div_table[] = { 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 *pm, unsigned int *pn, unsigned int *pod, + unsigned int *pod1) { unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1; -- 2.56.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes 2026-10-25 19:18 ` [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes H. Nikolaus Schaller @ 2026-10-25 22:54 ` Paul Cercueil 0 siblings, 0 replies; 12+ messages in thread From: Paul Cercueil @ 2026-10-25 22:54 UTC (permalink / raw) To: H. Nikolaus Schaller, Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel Hi Nikolaus, Le dimanche 25 octobre 2026 à 20:18 +0100, H. Nikolaus Schaller a écrit : > The common Ingenic CGU core framework was updated to support a > secondary post-VCO divider (OD1), which extended the signature of the > calc_m_n_od() callback. > > Update the JZ4760 CGU driver implementation to accept the new pod1 > argument, preventing compilation errors. The parameter remains unused > on this specific SoC architecture. > > Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> > --- > drivers/clk/ingenic/jz4760-cgu.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/clk/ingenic/jz4760-cgu.c > b/drivers/clk/ingenic/jz4760-cgu.c > index 372fe4b079927..52cc5ce150048 100644 > --- a/drivers/clk/ingenic/jz4760-cgu.c > +++ b/drivers/clk/ingenic/jz4760-cgu.c > @@ -56,7 +56,8 @@ static const u8 jz4760_cgu_pll_half_div_table[] = { > 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 *pm, unsigned int *pn, unsigned > int *pod, > + unsigned int *pod1) > { > unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1; > Well you can't update a callback prototype in patch 2/4 then update the implementations in 3/4, the kernel has to be buildable after each patch. Cheers, -Paul ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 4/4] clk: ingenic: x1000-cgu: Adapt calc_m_n_od() to core framework changes 2026-10-25 19:18 [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support H. Nikolaus Schaller ` (2 preceding siblings ...) 2026-10-25 19:18 ` [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes H. Nikolaus Schaller @ 2026-10-25 19:18 ` H. Nikolaus Schaller 3 siblings, 0 replies; 12+ messages in thread From: H. Nikolaus Schaller @ 2026-10-25 19:18 UTC (permalink / raw) To: Stephen Boyd, Brian Masney, Jerome Brunet, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Cercueil Cc: linux-clk, devicetree, linux-kernel, linux-mips, letux-kernel, kernel, H. Nikolaus Schaller The common Ingenic CGU core framework was updated to support a secondary post-VCO divider (OD1), which extended the signature of the calc_m_n_od() callback. Update the X1000 CGU driver implementation to accept the new pod1 argument, preventing compilation errors. The parameter remains unused on this specific SoC architecture. Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com> --- drivers/clk/ingenic/x1000-cgu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/x1000-cgu.c b/drivers/clk/ingenic/x1000-cgu.c index d89bdfb7c219a..cb82d8e6470b6 100644 --- a/drivers/clk/ingenic/x1000-cgu.c +++ b/drivers/clk/ingenic/x1000-cgu.c @@ -173,7 +173,8 @@ static const struct clk_ops x1000_otg_phy_ops = { static void x1000_i2spll_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 *pm, unsigned int *pn, unsigned int *pod, + unsigned int *pod1) { const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0); const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0); -- 2.56.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-11-11 21:52 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-25 19:18 [PATCH 0/4] clk / clocksource: Add Ingenic X1600 SoC support H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 1/4] dt-bindings: clock: Add Ingenic X1600 CGU bindings H. Nikolaus Schaller 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-30 11:24 ` Krzysztof Kozlowski 2026-10-30 12:06 ` H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 2/4] clk: ingenic: Add Ingenic X1600 CGU clock driver support H. Nikolaus Schaller 2026-10-26 10:16 ` kernel test robot 2026-11-11 21:43 ` Brian Masney 2026-11-11 21:51 ` H. Nikolaus Schaller 2026-10-25 19:18 ` [PATCH 3/4] clk: ingenic: jz4760-cgu: Adapt calc_m_n_od() to core framework changes H. Nikolaus Schaller 2026-10-25 22:54 ` Paul Cercueil 2026-10-25 19:18 ` [PATCH 4/4] clk: ingenic: x1000-cgu: " H. Nikolaus Schaller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox