* [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks
@ 2025-09-03 0:09 Andre Przywara
2025-09-03 0:09 ` [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Andre Przywara
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
Hi,
this series adds support for the CPU clock controller in the Allwinner
A523/A527/T527 family of SoCs.
In contrast to all earlier Allwinner SoCs, this chip features a separate
CCU for the CPU clocks (one for each of the two clusters) and the DSU
clock.
Patch 1/5 adds the binding document for the new CCU. This builds on top
of Chen-Yu's recent patch for the MCU PRCM, listed as a prerequisite
below.
Patch 2 and 3 add some slight enhancements to the sunxi-ng clock driver
framework, to generalise the update bit and allow clocks with just a
power-of-2 divider.
Patch 4 adds the actual clock driver, and patch 5 makes use of that by
adding the clock description to the SoC .dtsi.
Please have a look and test!
Cheers,
Andre
Andre Przywara (5):
dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller
clk: sunxi-ng: generalise update bit
clk: sunxi-ng: mp: support clocks with just a shift register
clk: sunxi-ng: add support for the A523/T527 CPU CCU
arm64: dts: allwinner: a523: add CPU clocks
.../clock/allwinner,sun55i-a523-ccu.yaml | 25 ++
.../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 22 ++
drivers/clk/sunxi-ng/Kconfig | 5 +
drivers/clk/sunxi-ng/Makefile | 2 +
drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c | 338 ++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h | 24 ++
drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 12 +-
drivers/clk/sunxi-ng/ccu_common.h | 5 +-
drivers/clk/sunxi-ng/ccu_div.c | 3 +-
drivers/clk/sunxi-ng/ccu_gate.c | 6 +-
drivers/clk/sunxi-ng/ccu_mp.c | 6 +-
drivers/clk/sunxi-ng/ccu_mp.h | 8 +-
drivers/clk/sunxi-ng/ccu_mux.c | 3 +-
drivers/clk/sunxi-ng/ccu_nm.c | 1 +
.../dt-bindings/clock/sun55i-a523-cpu-ccu.h | 13 +
15 files changed, 450 insertions(+), 23 deletions(-)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h
create mode 100644 include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
prerequisite-patch-id: 874f647e4961983cbcfda05d2fd906256b008327
--
2.46.3
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
@ 2025-09-03 0:09 ` Andre Przywara
2025-09-03 8:08 ` Krzysztof Kozlowski
2025-09-03 0:09 ` [PATCH 2/5] clk: sunxi-ng: generalise update bit Andre Przywara
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
There are four clock controllers in the A523 SoC, but only three are
described in the DT binding so far.
Add a description for the CPU CCU, which provides separate clocks for
the two CPU clusters and the DSU interconnect.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../clock/allwinner,sun55i-a523-ccu.yaml | 25 +++++++++++++++++++
.../dt-bindings/clock/sun55i-a523-cpu-ccu.h | 13 ++++++++++
2 files changed, 38 insertions(+)
create mode 100644 include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
index 1dbd92febc471..367d26800fd0d 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
@@ -19,6 +19,7 @@ properties:
compatible:
enum:
- allwinner,sun55i-a523-ccu
+ - allwinner,sun55i-a523-cpu-ccu
- allwinner,sun55i-a523-mcu-ccu
- allwinner,sun55i-a523-r-ccu
@@ -64,6 +65,30 @@ allOf:
- const: iosc
- const: losc-fanout
+ - if:
+ properties:
+ compatible:
+ enum:
+ - allwinner,sun55i-a523-cpu-ccu
+
+ then:
+ properties:
+ clocks:
+ items:
+ - description: High Frequency Oscillator (usually at 24MHz)
+ - description: Low Frequency Oscillator (usually at 32kHz)
+ - description: Internal Oscillator
+ - description: Peripherals PLL 0 (1200 MHz output)
+ - description: Peripherals PLL 0 (600 MHz output)
+
+ clock-names:
+ items:
+ - const: hosc
+ - const: losc
+ - const: iosc
+ - const: pll-periph0-2x
+ - const: pll-periph0-600m
+
- if:
properties:
compatible:
diff --git a/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
new file mode 100644
index 0000000000000..042f2310f64de
--- /dev/null
+++ b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright 2025 Arm Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
+#define _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
+
+#define CLK_CPU_L 7
+#define CLK_CPU_DSU 8
+#define CLK_CPU_B 9
+
+#endif /* _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_ */
--
2.46.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/5] clk: sunxi-ng: generalise update bit
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
2025-09-03 0:09 ` [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Andre Przywara
@ 2025-09-03 0:09 ` Andre Przywara
2025-09-03 0:09 ` [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register Andre Przywara
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
A few of the Allwinner A523 CCU clock registers introduced an "update" bit,
which must be set for changes to the other bits to take effect.
Of the three clocks where this was used, it was always bit 27, so we just
encoded this as a single bit feature flag.
Now the CPU PLL also features the update bit, but puts it at bit 26, so
this flag trick won't work anymore.
Add an "update_bit" field to the common sunxi clock struct, which takes a
bitmask, so we can encode any bit to use, even potentially multiple of
them. As uninitialised fields are set to 0, we can use this as a default
bitmask to set, so can OR this in unconditionally.
Change the existing update bit users to use this new encoding, and add
support for the ccu_nm clock on the way, since we will need it there
shortly.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 12 ++++++------
drivers/clk/sunxi-ng/ccu_common.h | 5 +----
drivers/clk/sunxi-ng/ccu_div.c | 3 +--
drivers/clk/sunxi-ng/ccu_gate.c | 6 ++----
drivers/clk/sunxi-ng/ccu_mp.h | 8 +++++---
drivers/clk/sunxi-ng/ccu_mux.c | 3 +--
drivers/clk/sunxi-ng/ccu_nm.c | 1 +
7 files changed, 17 insertions(+), 21 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
index 1a9a1cb869e23..736144f9e1833 100644
--- a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
+++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
@@ -385,8 +385,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents,
0, 0, /* no P */
24, 3, /* mux */
BIT(31), /* gate */
- CLK_IS_CRITICAL,
- CCU_FEATURE_UPDATE_BIT);
+ BIT(27), /* update*/
+ CLK_IS_CRITICAL, 0);
static const struct clk_hw *mbus_hws[] = { &mbus_clk.common.hw };
@@ -577,8 +577,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(iommu_clk, "iommu", iommu_parents,
0, 0, /* no P */
24, 3, /* mux */
BIT(31), /* gate */
- CLK_SET_RATE_PARENT,
- CCU_FEATURE_UPDATE_BIT);
+ BIT(27), /* update */
+ CLK_SET_RATE_PARENT, 0);
static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", apb0_hws, 0x7bc,
BIT(0), 0);
@@ -596,8 +596,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(dram_clk, "dram", dram_parents,
0, 0, /* no P */
24, 3, /* mux */
BIT(31), /* gate */
- CLK_IS_CRITICAL,
- CCU_FEATURE_UPDATE_BIT);
+ BIT(27), /* update*/
+ CLK_IS_CRITICAL, 0);
static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws,
0x804, BIT(0), 0);
diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h
index bbec283b9d993..e4caad2d8cef6 100644
--- a/drivers/clk/sunxi-ng/ccu_common.h
+++ b/drivers/clk/sunxi-ng/ccu_common.h
@@ -20,14 +20,10 @@
#define CCU_FEATURE_KEY_FIELD BIT(8)
#define CCU_FEATURE_CLOSEST_RATE BIT(9)
#define CCU_FEATURE_DUAL_DIV BIT(10)
-#define CCU_FEATURE_UPDATE_BIT BIT(11)
/* MMC timing mode switch bit */
#define CCU_MMC_NEW_TIMING_MODE BIT(30)
-/* Some clocks need this bit to actually apply register changes */
-#define CCU_SUNXI_UPDATE_BIT BIT(27)
-
struct device_node;
struct ccu_common {
@@ -35,6 +31,7 @@ struct ccu_common {
u16 reg;
u16 lock_reg;
u32 prediv;
+ u32 update_bit;
unsigned long min_rate;
unsigned long max_rate;
diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c
index 916d6da6d8a3b..fe97875f7c82d 100644
--- a/drivers/clk/sunxi-ng/ccu_div.c
+++ b/drivers/clk/sunxi-ng/ccu_div.c
@@ -106,8 +106,7 @@ static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
reg = readl(cd->common.base + cd->common.reg);
reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
- if (cd->common.features & CCU_FEATURE_UPDATE_BIT)
- reg |= CCU_SUNXI_UPDATE_BIT;
+ reg |= cd->common.update_bit;
writel(reg | (val << cd->div.shift),
cd->common.base + cd->common.reg);
diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c
index 30673fe4e3c2c..729d711c73fe7 100644
--- a/drivers/clk/sunxi-ng/ccu_gate.c
+++ b/drivers/clk/sunxi-ng/ccu_gate.c
@@ -20,8 +20,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
spin_lock_irqsave(common->lock, flags);
reg = readl(common->base + common->reg);
- if (common->features & CCU_FEATURE_UPDATE_BIT)
- reg |= CCU_SUNXI_UPDATE_BIT;
+ reg |= common->update_bit;
writel(reg & ~gate, common->base + common->reg);
spin_unlock_irqrestore(common->lock, flags);
@@ -46,8 +45,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
spin_lock_irqsave(common->lock, flags);
reg = readl(common->base + common->reg);
- if (common->features & CCU_FEATURE_UPDATE_BIT)
- reg |= CCU_SUNXI_UPDATE_BIT;
+ reg |= common->update_bit;
writel(reg | gate, common->base + common->reg);
spin_unlock_irqrestore(common->lock, flags);
diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h
index bb09c649bfa35..37d3128875194 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.h
+++ b/drivers/clk/sunxi-ng/ccu_mp.h
@@ -131,7 +131,8 @@ struct ccu_mp {
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
- _gate, _flags, _features) \
+ _gate, _update, \
+ _flags, _features) \
struct ccu_mp _struct = { \
.enable = _gate, \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
@@ -140,6 +141,7 @@ struct ccu_mp {
.common = { \
.reg = _reg, \
.features = _features, \
+ .update_bit = _update, \
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \
_parents, \
&ccu_mp_ops, \
@@ -156,7 +158,7 @@ struct ccu_mp {
_reg, _mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
- _gate, _flags, 0)
+ _gate, 0, _flags, 0)
#define SUNXI_CCU_DUALDIV_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
@@ -167,7 +169,7 @@ struct ccu_mp {
_reg, _mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
- _gate, _flags, \
+ _gate, 0, _flags, \
CCU_FEATURE_DUAL_DIV)
#define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg, \
diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c
index 74f9e98a5d355..8ff9f15bab0bd 100644
--- a/drivers/clk/sunxi-ng/ccu_mux.c
+++ b/drivers/clk/sunxi-ng/ccu_mux.c
@@ -197,8 +197,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common,
/* The key field always reads as zero. */
if (common->features & CCU_FEATURE_KEY_FIELD)
reg |= CCU_MUX_KEY_VALUE;
- if (common->features & CCU_FEATURE_UPDATE_BIT)
- reg |= CCU_SUNXI_UPDATE_BIT;
+ reg |= common->update_bit;
reg &= ~GENMASK(cm->width + cm->shift - 1, cm->shift);
writel(reg | (index << cm->shift), common->base + common->reg);
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index df01ed3b37a6b..e502b9c78c1b1 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -219,6 +219,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
reg |= (_nm.n - nm->n.offset) << nm->n.shift;
reg |= (_nm.m - nm->m.offset) << nm->m.shift;
+ reg |= nm->common.update_bit;
writel(reg, nm->common.base + nm->common.reg);
spin_unlock_irqrestore(nm->common.lock, flags);
--
2.46.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
2025-09-03 0:09 ` [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Andre Przywara
2025-09-03 0:09 ` [PATCH 2/5] clk: sunxi-ng: generalise update bit Andre Przywara
@ 2025-09-03 0:09 ` Andre Przywara
2025-09-03 4:20 ` Chen-Yu Tsai
2025-09-03 0:09 ` [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU Andre Przywara
2025-09-03 0:09 ` [PATCH 5/5] arm64: dts: allwinner: a523: add CPU clocks Andre Przywara
4 siblings, 1 reply; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
The "mp" clock models a mod clock with divider and a shift field. At
least one clock in the Allwinner A523 features just a power-of-2 divider
field, so support an initialisation of the clock without providing an
actual divider field.
Add a check whether the "width" field is 0, and skip the divider
handling in this case, as the GENMASK macro will not work with a zero
length.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/clk/sunxi-ng/ccu_mp.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index 354c981943b6f..a03dac294d048 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -236,9 +236,11 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(cmp->common.lock, flags);
reg = readl(cmp->common.base + cmp->common.reg);
- reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
+ if (cmp->m.width)
+ reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
- reg |= (m - cmp->m.offset) << cmp->m.shift;
+ if (cmp->m.width)
+ reg |= (m - cmp->m.offset) << cmp->m.shift;
if (shift)
reg |= ilog2(p) << cmp->p.shift;
else
--
2.46.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
` (2 preceding siblings ...)
2025-09-03 0:09 ` [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register Andre Przywara
@ 2025-09-03 0:09 ` Andre Przywara
2025-09-03 10:26 ` Krzysztof Kozlowski
2025-09-03 0:09 ` [PATCH 5/5] arm64: dts: allwinner: a523: add CPU clocks Andre Przywara
4 siblings, 1 reply; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
The A523 contains a separate CCU block for the CPU PLLs. This includes
one CPU clock per cluster, plus the DSU PLL, which clocks the part that
connects the two clusters, and in particular the L3 cache.
There is also an undocumented PLL0, which is a simper model that can
apparently be used as an interim clock while re-locking the original
PLLs.
Add the PLL clocks for the CPU PLLs. This particular clock tree is a bit
weird, as there is a divider field for the just the PLL, but inside the
mux clock. The ASCII art should explain this better. Model those as three
separate clocks, and expose just the final mux clock for both clusters
and the DSU.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/clk/sunxi-ng/Kconfig | 5 +
drivers/clk/sunxi-ng/Makefile | 2 +
drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c | 338 +++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h | 24 ++
4 files changed, 369 insertions(+)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 8896fd052ef17..24902287efc88 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -62,6 +62,11 @@ config SUN55I_A523_R_CCU
default ARCH_SUNXI
depends on ARM64 || COMPILE_TEST
+config SUN55I_A523_CPU_CCU
+ tristate "Support for the Allwinner A523/T527 CPU CCU"
+ default y
+ depends on ARM64 || COMPILE_TEST
+
config SUN4I_A10_CCU
tristate "Support for the Allwinner A10/A20 CCU"
default ARCH_SUNXI
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 82e471036de69..d0db2991a8673 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_SUN50I_H6_R_CCU) += sun50i-h6-r-ccu.o
obj-$(CONFIG_SUN50I_H616_CCU) += sun50i-h616-ccu.o
obj-$(CONFIG_SUN55I_A523_CCU) += sun55i-a523-ccu.o
obj-$(CONFIG_SUN55I_A523_R_CCU) += sun55i-a523-r-ccu.o
+obj-$(CONFIG_SUN55I_A523_CPU_CCU) += sun55i-a523-cpu-ccu.o
obj-$(CONFIG_SUN4I_A10_CCU) += sun4i-a10-ccu.o
obj-$(CONFIG_SUN5I_CCU) += sun5i-ccu.o
obj-$(CONFIG_SUN6I_A31_CCU) += sun6i-a31-ccu.o
@@ -62,6 +63,7 @@ sun50i-h6-r-ccu-y += ccu-sun50i-h6-r.o
sun50i-h616-ccu-y += ccu-sun50i-h616.o
sun55i-a523-ccu-y += ccu-sun55i-a523.o
sun55i-a523-r-ccu-y += ccu-sun55i-a523-r.o
+sun55i-a523-cpu-ccu-y += ccu-sun55i-a523-cpu.o
sun4i-a10-ccu-y += ccu-sun4i-a10.o
sun5i-ccu-y += ccu-sun5i.o
sun6i-a31-ccu-y += ccu-sun6i-a31.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c
new file mode 100644
index 0000000000000..b17a830b42477
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023-2025 Arm Ltd.
+ *
+ * There are four PLLs: one for the little cluster (cores 0-3: PLL1), one for
+ * the "big" cluster (cores 4-7: PLL3), one for the DSU interconnect (probably
+ * its SCLK, driving the L3 cache: PLL2), and one undocumented "backup" PLL0,
+ * which can be used to drive either or both clusters, while the original PLLs
+ * are re-programmed (and re-lock).
+ * PLL[123] are the same, with a multiplier, a predivider, and two separate
+ * divider fields. For PLL1 and PLL3 there is an additional shift field, in
+ * the mux clock - although that applies only to the PLL, not the other sources.
+ * The two clusters and the DSU are connected to a mux clock each, selecting
+ * from various sources, including the PLL-PERIPH0-600M clock, again useful
+ * during DVFS operations:
+ *
+ * PLL-PERI0-600M (from the main CCU)
+ * |
+ * +-------+-----------+
+ * / \ \
+ * +------+ / +------+ \ +------+ \ +------+
+ * | PLL1 | | | PLL0 | | | PLL3 | | | PLL2 |
+ * +------+ | +------+ | +------+ | +------+
+ * \ | ^ | / | /
+ * DIV | / \ | DIV | / (plus 24MHz,
+ * \ | / \ | / | | 32KHz,
+ * +---------+ +---------+ +---------+ 16MHz,
+ * \ CPU-L / \ CPU-B / \ DSU / for each mux)
+ * \ / \ / \ /
+ * +---+ +---+ +---+
+ * | | |
+ * +-------+-----------+-----DSU-----+----+
+ * | +---+---+ +---+---+ |
+ * | | cores | | cores | |
+ * | | 0-3 | | 4-7 | +------------+
+ * | +-------+ +-------+ | L3 cache |
+ * +-------------------------+------------+
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_nm.h"
+#include "ccu_mult.h"
+
+#include "ccu-sun55i-a523-cpu.h"
+
+/*
+ * The 24 MHz oscillator, the root of most of the clock tree.
+ * .fw_name is the string used in the DT "clock-names" property, used to
+ * identify the corresponding clock in the "clocks" property.
+ */
+static const struct clk_parent_data osc24M[] = {
+ { .fw_name = "hosc" }
+};
+
+/*
+ * Undocumented PLL, mux-able to both clusters, usable as an interim PLL
+ * during DVFS clock rate changes. Bits [23:16] and [4:2] are RAZ/WI, which
+ * looks like the DDR or VIDEO PLLs, and not like the other CPU PLLs.
+ * Bits [1:0] are not dividers, as they don't have any effect on the frequency.
+ */
+#define SUN55I_A523_PLL_CPU_0_REG 0x00
+
+static struct ccu_mult pll_cpu_0_clk = {
+ .enable = BIT(27),
+ .lock = BIT(28),
+ .mult = _SUNXI_CCU_MULT(8, 8),
+ .common = {
+ .reg = 0x00,
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-0", osc24M,
+ &ccu_mult_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+static const struct clk_parent_data pll_cpu_0_hws[] = {
+ { .hw = &pll_cpu_0_clk.common.hw },
+};
+
+/*
+ * The PLLs are input * N / P / (M0 * M1). Model them as NM, by ignoring the
+ * predivider P and the only 2-bit wide M0, and fixing them to 1 in probe().
+ * Using NKMP wouldn't be better, because the "P" in there is a shift.
+ * The actual enable bit is bit 31, which we set once in probe, along with
+ * some other control bits, as the manual recommends to not touch them
+ * during runtime.
+ */
+#define SUN55I_A523_PLL_CPU_L_REG 0x04
+static struct ccu_nm pll_cpu_l_clk = {
+ .enable = BIT(27),
+ .lock = BIT(28),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108),
+ .m = _SUNXI_CCU_DIV(0, 3), /* M1 */
+ .common = {
+ .reg = 0x04,
+ .update_bit = BIT(26),
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-l", osc24M,
+ &ccu_nm_ops,
+ CLK_SET_RATE_UNGATE |
+ CLK_IS_CRITICAL),
+ },
+};
+static const struct clk_parent_data pll_cpu_l_hws[] = {
+ { .hw = &pll_cpu_l_clk.common.hw },
+};
+
+#define SUN55I_A523_PLL_CPU_DSU_REG 0x08
+static struct ccu_nm pll_cpu_dsu_clk = {
+ .enable = BIT(27),
+ .lock = BIT(28),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108),
+ .m = _SUNXI_CCU_DIV(0, 3), /* M1 */
+ .common = {
+ .reg = 0x08,
+ .update_bit = BIT(26),
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-dsu", osc24M,
+ &ccu_nm_ops,
+ CLK_SET_RATE_UNGATE |
+ CLK_IS_CRITICAL),
+ },
+};
+static const struct clk_parent_data pll_cpu_dsu_hws[] = {
+ { .hw = &pll_cpu_dsu_clk.common.hw },
+};
+
+
+#define SUN55I_A523_PLL_CPU_B_REG 0x0c
+static struct ccu_nm pll_cpu_b_clk = {
+ .enable = BIT(27),
+ .lock = BIT(28),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108),
+ .m = _SUNXI_CCU_DIV(0, 3), /* M1 */
+ .common = {
+ .reg = 0x0c,
+ .update_bit = BIT(26),
+ .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-b", osc24M,
+ &ccu_nm_ops,
+ CLK_SET_RATE_UNGATE |
+ CLK_IS_CRITICAL),
+ },
+};
+static const struct clk_parent_data pll_cpu_b_hws[] = {
+ { .hw = &pll_cpu_b_clk.common.hw },
+};
+
+static SUNXI_CCU_MP_DATA_WITH_MUX(pll_cpu_l_div_clk, "pll-cpu-l-div",
+ pll_cpu_l_hws, 0x060,
+ 0, 0, /* no M */
+ 16, 2, /* P */
+ 0, 0, /* no mux */
+ CLK_SET_RATE_PARENT); /* flags */
+static SUNXI_CCU_MP_DATA_WITH_MUX(pll_cpu_b_div_clk, "pll-cpu-b-div",
+ pll_cpu_b_hws, 0x064,
+ 0, 0, /* no M */
+ 16, 2, /* P */
+ 0, 0, /* no mux */
+ CLK_SET_RATE_PARENT); /* flags */
+static SUNXI_CCU_MP_DATA_WITH_MUX(pll_cpu_dsu_div_clk, "pll-cpu-dsu-div",
+ pll_cpu_dsu_hws, 0x06c,
+ 0, 0, /* no M */
+ 16, 2, /* P */
+ 0, 0, /* no mux */
+ CLK_SET_RATE_PARENT); /* flags */
+
+static const struct clk_parent_data cpu_l_parents[] = {
+ { .fw_name = "hosc" },
+ { .fw_name = "losc" },
+ { .fw_name = "iosc" },
+ { .hw = &pll_cpu_l_div_clk.common.hw },
+ { .fw_name = "pll-periph0-600M" },
+ { .hw = &pll_cpu_0_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA(cpu_l_clk, "cpu-l", cpu_l_parents, 0x60,
+ 24, 3, /* mux */
+ CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+
+static const struct clk_parent_data cpu_b_parents[] = {
+ { .fw_name = "hosc" },
+ { .fw_name = "losc" },
+ { .fw_name = "iosc" },
+ { .hw = &pll_cpu_b_div_clk.common.hw },
+ { .fw_name = "pll-periph0-600M" },
+ { .hw = &pll_cpu_0_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA(cpu_b_clk, "cpu-b", cpu_b_parents, 0x64,
+ 24, 3, /* mux */
+ CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+/*
+ * Register 0x68 holds gate bits for the two cluster clocks and the DSU.
+ * We leave them alone in the kernel, that's something for TF-A or the SCP.
+ */
+
+static const struct clk_parent_data cpu_dsu_parents[] = {
+ { .fw_name = "hosc" },
+ { .fw_name = "losc" },
+ { .fw_name = "iosc" },
+ { .hw = &pll_cpu_dsu_div_clk.common.hw },
+ { .fw_name = "pll-periph0-2x" },
+ { .fw_name = "pll-periph0-600M" },
+};
+static SUNXI_CCU_MUX_DATA(cpu_dsu_clk, "cpu-dsu", cpu_dsu_parents, 0x6c,
+ 24, 3, /* mux */
+ CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static struct ccu_common *sun55i_a523_cpu_ccu_clks[] = {
+ &pll_cpu_0_clk.common,
+ &pll_cpu_l_clk.common,
+ &pll_cpu_b_clk.common,
+ &pll_cpu_dsu_clk.common,
+ &pll_cpu_l_div_clk.common,
+ &pll_cpu_b_div_clk.common,
+ &pll_cpu_dsu_div_clk.common,
+ &cpu_l_clk.common,
+ &cpu_b_clk.common,
+ &cpu_dsu_clk.common,
+};
+
+static struct clk_hw_onecell_data sun55i_a523_cpu_hw_clks = {
+ .hws = {
+ [CLK_PLL_CPU_0] = &pll_cpu_0_clk.common.hw,
+ [CLK_PLL_CPU_L] = &pll_cpu_l_clk.common.hw,
+ [CLK_PLL_CPU_DSU] = &pll_cpu_dsu_clk.common.hw,
+ [CLK_PLL_CPU_B] = &pll_cpu_b_clk.common.hw,
+ [CLK_DIV_CPU_L] = &pll_cpu_l_div_clk.common.hw,
+ [CLK_DIV_CPU_DSU] = &pll_cpu_dsu_div_clk.common.hw,
+ [CLK_DIV_CPU_B] = &pll_cpu_b_div_clk.common.hw,
+ [CLK_CPU_L] = &cpu_l_clk.common.hw,
+ [CLK_CPU_DSU] = &cpu_dsu_clk.common.hw,
+ [CLK_CPU_B] = &cpu_b_clk.common.hw,
+ },
+ .num = CLK_NUMBER,
+};
+
+static const struct sunxi_ccu_desc sun55i_a523_cpu_ccu_desc = {
+ .ccu_clks = sun55i_a523_cpu_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sun55i_a523_cpu_ccu_clks),
+
+ .hw_clks = &sun55i_a523_cpu_hw_clks,
+};
+
+static const u32 pll_regs[] = {
+ SUN55I_A523_PLL_CPU_0_REG,
+ SUN55I_A523_PLL_CPU_L_REG,
+ SUN55I_A523_PLL_CPU_DSU_REG,
+ SUN55I_A523_PLL_CPU_B_REG,
+};
+
+static struct ccu_mux_nb sun55i_a523_cpu_l_nb = {
+ .common = &cpu_l_clk.common,
+ .cm = &cpu_l_clk.mux,
+ .delay_us = 1, /* manual doesn't really say */
+ .bypass_index = 4, /* PLL_PERI0@600MHz, as recommended by manual */
+};
+static struct ccu_mux_nb sun55i_a523_cpu_b_nb = {
+ .common = &cpu_b_clk.common,
+ .cm = &cpu_b_clk.mux,
+ .delay_us = 1, /* manual doesn't really say */
+ .bypass_index = 4, /* PLL_PERI0@600MHz, as recommended by manual */
+};
+
+static int sun55i_a523_cpu_ccu_probe(struct platform_device *pdev)
+{
+ const struct sunxi_ccu_desc *desc;
+ void __iomem *reg;
+ int i, ret;
+ u32 val;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ /*
+ * The user manual recommends to keep the PLLs running, and just
+ * gate their output if they are not needed, to avoid interference
+ * with other PLLs, since they share a power domain.
+ * To comply with this, we use this output gate as the CCF enable bit,
+ * so we need to enable all PLLs here. Chances are the bootloader has
+ * already enabled at least one PLL, so check if it's already running
+ * and locked, before touching it.
+ * We set the enable, the LDO and the lock bits, and clear dividers.
+ */
+ for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
+ val = readl(reg + pll_regs[i]);
+ if ((val & GENMASK(31, 28)) != GENMASK(31, 28)) {
+ val |= BIT(31) | BIT(30) | BIT(29) | BIT(26);
+ val &= ~GENMASK(21, 16); /* covering PLL_P and PLL_M0 */
+ writel(val, reg + pll_regs[i]);
+ }
+ }
+
+ ret = devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+ if (ret)
+ return ret;
+
+ /* Reparent CPU during CPU PLL rate changes */
+ ccu_mux_notifier_register(pll_cpu_l_clk.common.hw.clk,
+ &sun55i_a523_cpu_l_nb);
+ ccu_mux_notifier_register(pll_cpu_b_clk.common.hw.clk,
+ &sun55i_a523_cpu_b_nb);
+
+ return ret;
+}
+
+static const struct of_device_id sun55i_a523_cpu_ccu_ids[] = {
+ {
+ .compatible = "allwinner,sun55i-a523-cpu-ccu",
+ .data = &sun55i_a523_cpu_ccu_desc,
+ },
+ { }
+};
+
+static struct platform_driver sun55i_a523_cpu_ccu_driver = {
+ .probe = sun55i_a523_cpu_ccu_probe,
+ .driver = {
+ .name = "sun55i-a523-cpu-ccu",
+ .suppress_bind_attrs = true,
+ .of_match_table = sun55i_a523_cpu_ccu_ids,
+ },
+};
+module_platform_driver(sun55i_a523_cpu_ccu_driver);
+
+MODULE_IMPORT_NS("SUNXI_CCU");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h
new file mode 100644
index 0000000000000..484343b2c4fa6
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2025 Arm Ltd.
+ */
+
+#ifndef _CCU_SUN55I_A523_CPU_H
+#define _CCU_SUN55I_A523_CPU_H
+
+#include <dt-bindings/clock/sun55i-a523-cpu-ccu.h>
+
+/* The PLL clocks itself and the pure divider clocks are not exported. */
+
+#define CLK_PLL_CPU_0 0
+#define CLK_PLL_CPU_L 1
+#define CLK_PLL_CPU_DSU 2
+#define CLK_PLL_CPU_B 3
+
+#define CLK_DIV_CPU_L 4
+#define CLK_DIV_CPU_DSU 5
+#define CLK_DIV_CPU_B 6
+
+#define CLK_NUMBER (CLK_CPU_B + 1)
+
+#endif /* _CCU_SUN55I_A523_CPU_H */
--
2.46.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/5] arm64: dts: allwinner: a523: add CPU clocks
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
` (3 preceding siblings ...)
2025-09-03 0:09 ` [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU Andre Przywara
@ 2025-09-03 0:09 ` Andre Przywara
4 siblings, 0 replies; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 0:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
The Allwinner A523 family of SoCs feature a separate clock unit for the
CPU PLLs and muxes, including one for the DSU interconnect.
Add a DT node for the CPU clock controller, and list all the clocks from
the other CCUs that this controller needs.
Also list the clock source for each CPU: there is one clock for each
cluster of four cores, suffixed L and B, for little and big (although
all cores are of the same Cortex-A55 type).
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index 6b6f2296bdff6..98a59d324bfeb 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -5,6 +5,7 @@
#include <dt-bindings/clock/sun6i-rtc.h>
#include <dt-bindings/clock/sun55i-a523-ccu.h>
#include <dt-bindings/clock/sun55i-a523-r-ccu.h>
+#include <dt-bindings/clock/sun55i-a523-cpu-ccu.h>
#include <dt-bindings/reset/sun55i-a523-ccu.h>
#include <dt-bindings/reset/sun55i-a523-r-ccu.h>
#include <dt-bindings/power/allwinner,sun55i-a523-ppu.h>
@@ -24,6 +25,7 @@ cpu0: cpu@0 {
device_type = "cpu";
reg = <0x000>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_L>;
};
cpu1: cpu@100 {
@@ -31,6 +33,7 @@ cpu1: cpu@100 {
device_type = "cpu";
reg = <0x100>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_L>;
};
cpu2: cpu@200 {
@@ -38,6 +41,7 @@ cpu2: cpu@200 {
device_type = "cpu";
reg = <0x200>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_L>;
};
cpu3: cpu@300 {
@@ -45,6 +49,7 @@ cpu3: cpu@300 {
device_type = "cpu";
reg = <0x300>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_L>;
};
cpu4: cpu@400 {
@@ -52,6 +57,7 @@ cpu4: cpu@400 {
device_type = "cpu";
reg = <0x400>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_B>;
};
cpu5: cpu@500 {
@@ -59,6 +65,7 @@ cpu5: cpu@500 {
device_type = "cpu";
reg = <0x500>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_B>;
};
cpu6: cpu@600 {
@@ -66,6 +73,7 @@ cpu6: cpu@600 {
device_type = "cpu";
reg = <0x600>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_B>;
};
cpu7: cpu@700 {
@@ -73,6 +81,7 @@ cpu7: cpu@700 {
device_type = "cpu";
reg = <0x700>;
enable-method = "psci";
+ clocks = <&cpu_ccu CLK_CPU_B>;
};
};
@@ -690,5 +699,18 @@ rtc: rtc@7090000 {
clock-names = "bus", "hosc", "ahb";
#clock-cells = <1>;
};
+
+ cpu_ccu: clock-controller@8817000 {
+ compatible = "allwinner,sun55i-a523-cpu-ccu";
+ reg = <0x08817000 0x80>;
+ clocks = <&osc24M>, <&rtc CLK_OSC32K>,
+ <&rtc CLK_IOSC>, <&ccu CLK_PLL_PERIPH0_2X>,
+ <&ccu CLK_PLL_PERIPH0_600M>;
+ clock-names = "hosc", "losc",
+ "iosc", "pll-periph0-2x",
+ "pll-periph0-600M";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
};
};
--
2.46.3
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register
2025-09-03 0:09 ` [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register Andre Przywara
@ 2025-09-03 4:20 ` Chen-Yu Tsai
2025-09-03 10:20 ` Andre Przywara
0 siblings, 1 reply; 12+ messages in thread
From: Chen-Yu Tsai @ 2025-09-03 4:20 UTC (permalink / raw)
To: Andre Przywara
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Samuel Holland, linux-clk,
devicetree, linux-arm-kernel, linux-sunxi, Mikhail Kalashnikov
On Wed, Sep 3, 2025 at 8:09 AM Andre Przywara <andre.przywara@arm.com> wrote:
>
> The "mp" clock models a mod clock with divider and a shift field. At
> least one clock in the Allwinner A523 features just a power-of-2 divider
> field, so support an initialisation of the clock without providing an
> actual divider field.
>
> Add a check whether the "width" field is 0, and skip the divider
> handling in this case, as the GENMASK macro will not work with a zero
> length.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
In my series I have a patch that adds this to the divider clocks,
thus adding a P-clock type to the M-clock bits.
Maybe use that instead? I prefer we use actual matching types instead
of disabling one part of a complex clock type.
ChenYu
> drivers/clk/sunxi-ng/ccu_mp.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
> index 354c981943b6f..a03dac294d048 100644
> --- a/drivers/clk/sunxi-ng/ccu_mp.c
> +++ b/drivers/clk/sunxi-ng/ccu_mp.c
> @@ -236,9 +236,11 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
> spin_lock_irqsave(cmp->common.lock, flags);
>
> reg = readl(cmp->common.base + cmp->common.reg);
> - reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
> + if (cmp->m.width)
> + reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
> reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
> - reg |= (m - cmp->m.offset) << cmp->m.shift;
> + if (cmp->m.width)
> + reg |= (m - cmp->m.offset) << cmp->m.shift;
> if (shift)
> reg |= ilog2(p) << cmp->p.shift;
> else
> --
> 2.46.3
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller
2025-09-03 0:09 ` [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Andre Przywara
@ 2025-09-03 8:08 ` Krzysztof Kozlowski
2025-09-03 9:46 ` Andre Przywara
0 siblings, 1 reply; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-03 8:08 UTC (permalink / raw)
To: Andre Przywara
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland,
linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
On Wed, Sep 03, 2025 at 01:09:06AM +0100, Andre Przywara wrote:
> There are four clock controllers in the A523 SoC, but only three are
> described in the DT binding so far.
>
> Add a description for the CPU CCU, which provides separate clocks for
> the two CPU clusters and the DSU interconnect.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> .../clock/allwinner,sun55i-a523-ccu.yaml | 25 +++++++++++++++++++
> .../dt-bindings/clock/sun55i-a523-cpu-ccu.h | 13 ++++++++++
> 2 files changed, 38 insertions(+)
> create mode 100644 include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
>
> diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> index 1dbd92febc471..367d26800fd0d 100644
> --- a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> +++ b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> @@ -19,6 +19,7 @@ properties:
> compatible:
> enum:
> - allwinner,sun55i-a523-ccu
> + - allwinner,sun55i-a523-cpu-ccu
> - allwinner,sun55i-a523-mcu-ccu
> - allwinner,sun55i-a523-r-ccu
>
> @@ -64,6 +65,30 @@ allOf:
> - const: iosc
> - const: losc-fanout
>
> + - if:
> + properties:
> + compatible:
> + enum:
> + - allwinner,sun55i-a523-cpu-ccu
> +
> + then:
> + properties:
> + clocks:
> + items:
> + - description: High Frequency Oscillator (usually at 24MHz)
> + - description: Low Frequency Oscillator (usually at 32kHz)
> + - description: Internal Oscillator
> + - description: Peripherals PLL 0 (1200 MHz output)
> + - description: Peripherals PLL 0 (600 MHz output)
> +
> + clock-names:
> + items:
> + - const: hosc
> + - const: losc
> + - const: iosc
> + - const: pll-periph0-2x
> + - const: pll-periph0-600m
> +
> - if:
> properties:
> compatible:
> diff --git a/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
> new file mode 100644
> index 0000000000000..042f2310f64de
> --- /dev/null
> +++ b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
Filename based on compatible.
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
> +/*
> + * Copyright 2025 Arm Ltd.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
> +#define _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
> +
> +#define CLK_CPU_L 7
> +#define CLK_CPU_DSU 8
> +#define CLK_CPU_B 9
I don't see the header being used by the driver and odd numbers (they
should start from 0 or 1) suggest these are not bindings.
Otherwise please explain in commit msg what exactly are you binding
here.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller
2025-09-03 8:08 ` Krzysztof Kozlowski
@ 2025-09-03 9:46 ` Andre Przywara
2025-09-03 10:25 ` Krzysztof Kozlowski
0 siblings, 1 reply; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 9:46 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland,
linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
On Wed, 3 Sep 2025 10:08:33 +0200
Krzysztof Kozlowski <krzk@kernel.org> wrote:
Hi,
> On Wed, Sep 03, 2025 at 01:09:06AM +0100, Andre Przywara wrote:
> > There are four clock controllers in the A523 SoC, but only three are
> > described in the DT binding so far.
> >
> > Add a description for the CPU CCU, which provides separate clocks for
> > the two CPU clusters and the DSU interconnect.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> > .../clock/allwinner,sun55i-a523-ccu.yaml | 25 +++++++++++++++++++
> > .../dt-bindings/clock/sun55i-a523-cpu-ccu.h | 13 ++++++++++
> > 2 files changed, 38 insertions(+)
> > create mode 100644 include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
> >
> > diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> > index 1dbd92febc471..367d26800fd0d 100644
> > --- a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> > +++ b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml
> > @@ -19,6 +19,7 @@ properties:
> > compatible:
> > enum:
> > - allwinner,sun55i-a523-ccu
> > + - allwinner,sun55i-a523-cpu-ccu
> > - allwinner,sun55i-a523-mcu-ccu
> > - allwinner,sun55i-a523-r-ccu
> >
> > @@ -64,6 +65,30 @@ allOf:
> > - const: iosc
> > - const: losc-fanout
> >
> > + - if:
> > + properties:
> > + compatible:
> > + enum:
> > + - allwinner,sun55i-a523-cpu-ccu
> > +
> > + then:
> > + properties:
> > + clocks:
> > + items:
> > + - description: High Frequency Oscillator (usually at 24MHz)
> > + - description: Low Frequency Oscillator (usually at 32kHz)
> > + - description: Internal Oscillator
> > + - description: Peripherals PLL 0 (1200 MHz output)
> > + - description: Peripherals PLL 0 (600 MHz output)
> > +
> > + clock-names:
> > + items:
> > + - const: hosc
> > + - const: losc
> > + - const: iosc
> > + - const: pll-periph0-2x
> > + - const: pll-periph0-600m
> > +
> > - if:
> > properties:
> > compatible:
> > diff --git a/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
> > new file mode 100644
> > index 0000000000000..042f2310f64de
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h
>
> Filename based on compatible.
>
>
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
> > +/*
> > + * Copyright 2025 Arm Ltd.
> > + */
> > +
> > +#ifndef _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
> > +#define _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
> > +
> > +#define CLK_CPU_L 7
> > +#define CLK_CPU_DSU 8
> > +#define CLK_CPU_B 9
>
> I don't see the header being used by the driver and odd numbers (they
> should start from 0 or 1) suggest these are not bindings.
This header is included by the private header (at the end of patch 4/5).
The private header is then included by the driver.
Happy to change that, but that's the pattern used in all the other drivers.
Those numbers represent the publicly exposed clocks, the other clocks are
internal. Having gaps in those numbers is somewhat common in sunxi-ng
(check sun50i-h616-ccu.h). This large gap at the beginning here is mostly
due to the somewhat extreme design of this CCU, which requires quite some
helper clocks to get to the actual ones.
We could sort the identifiers to have the public clocks first, but
that would only be the case until we discover a missed clock (which seems
to happen from times to times). And again, that's the pattern used in the
sibling drivers, so I'd rather stay consistent here.
Cheers,
Andre
> Otherwise please explain in commit msg what exactly are you binding
> here.
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register
2025-09-03 4:20 ` Chen-Yu Tsai
@ 2025-09-03 10:20 ` Andre Przywara
0 siblings, 0 replies; 12+ messages in thread
From: Andre Przywara @ 2025-09-03 10:20 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Samuel Holland, linux-clk,
devicetree, linux-arm-kernel, linux-sunxi, Mikhail Kalashnikov
On Wed, 3 Sep 2025 12:20:55 +0800
Chen-Yu Tsai <wens@csie.org> wrote:
> On Wed, Sep 3, 2025 at 8:09 AM Andre Przywara <andre.przywara@arm.com> wrote:
> >
> > The "mp" clock models a mod clock with divider and a shift field. At
> > least one clock in the Allwinner A523 features just a power-of-2 divider
> > field, so support an initialisation of the clock without providing an
> > actual divider field.
> >
> > Add a check whether the "width" field is 0, and skip the divider
> > handling in this case, as the GENMASK macro will not work with a zero
> > length.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
>
> In my series I have a patch that adds this to the divider clocks,
> thus adding a P-clock type to the M-clock bits.
Yeah, I saw that, but wasn't convinced this would be better. Hence wanted
to post my version as an alternative.
> Maybe use that instead? I prefer we use actual matching types instead
> of disabling one part of a complex clock type.
Good that you bring up that topic: when looking for matching clocks I saw
we have a lot of them, though often one is just a subset of some others,
with some code duplication. And we use the pattern of "use type A, but
without feature X" already, for instance for "NKMP without the K".
So I was wondering if we should revisit this and clean this up. IIUC those
clocks were all modelled after the H3 and earlier generation, and the
clocks have changed since then. For instance I don't see PLLs with two
multipliers (NK) after the A64 anymore.
So what about we consolidate the various types into just a few distinct
ones, like NKMP for all PLLs, for instance, and provides macros that
disable fields as needed? This could ideally be done under the hood,
leaving the per-SoC drivers mostly alone, hopefully.
What do people think about that?
Cheers,
Andre
> > drivers/clk/sunxi-ng/ccu_mp.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
> > index 354c981943b6f..a03dac294d048 100644
> > --- a/drivers/clk/sunxi-ng/ccu_mp.c
> > +++ b/drivers/clk/sunxi-ng/ccu_mp.c
> > @@ -236,9 +236,11 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
> > spin_lock_irqsave(cmp->common.lock, flags);
> >
> > reg = readl(cmp->common.base + cmp->common.reg);
> > - reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
> > + if (cmp->m.width)
> > + reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
> > reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
> > - reg |= (m - cmp->m.offset) << cmp->m.shift;
> > + if (cmp->m.width)
> > + reg |= (m - cmp->m.offset) << cmp->m.shift;
> > if (shift)
> > reg |= ilog2(p) << cmp->p.shift;
> > else
> > --
> > 2.46.3
> >
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller
2025-09-03 9:46 ` Andre Przywara
@ 2025-09-03 10:25 ` Krzysztof Kozlowski
0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-03 10:25 UTC (permalink / raw)
To: Andre Przywara
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jernej Skrabec, Chen-Yu Tsai, Samuel Holland,
linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
On 03/09/2025 11:46, Andre Przywara wrote:
>>
>>
>>> @@ -0,0 +1,13 @@
>>> +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
>>> +/*
>>> + * Copyright 2025 Arm Ltd.
>>> + */
>>> +
>>> +#ifndef _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
>>> +#define _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_
>>> +
>>> +#define CLK_CPU_L 7
>>> +#define CLK_CPU_DSU 8
>>> +#define CLK_CPU_B 9
>>
>> I don't see the header being used by the driver and odd numbers (they
>> should start from 0 or 1) suggest these are not bindings.
>
> This header is included by the private header (at the end of patch 4/5).
> The private header is then included by the driver.
Ah, I see now.
>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU
2025-09-03 0:09 ` [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU Andre Przywara
@ 2025-09-03 10:26 ` Krzysztof Kozlowski
0 siblings, 0 replies; 12+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-03 10:26 UTC (permalink / raw)
To: Andre Przywara, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Jernej Skrabec, Chen-Yu Tsai,
Samuel Holland
Cc: linux-clk, devicetree, linux-arm-kernel, linux-sunxi,
Mikhail Kalashnikov
On 03/09/2025 02:09, Andre Przywara wrote:
> +#include "ccu_common.h"
> +#include "ccu_reset.h"
> +
> +#include "ccu_div.h"
> +#include "ccu_gate.h"
> +#include "ccu_mp.h"
> +#include "ccu_nm.h"
> +#include "ccu_mult.h"
> +
> +#include "ccu-sun55i-a523-cpu.h"
You should not rely on some other headers pulling other headers. You use
here bindings, so you should include here bindings header as well.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-09-03 10:26 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-03 0:09 [PATCH 0/5] arm64: allwinner: a523: Enable CPU clocks Andre Przywara
2025-09-03 0:09 ` [PATCH 1/5] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Andre Przywara
2025-09-03 8:08 ` Krzysztof Kozlowski
2025-09-03 9:46 ` Andre Przywara
2025-09-03 10:25 ` Krzysztof Kozlowski
2025-09-03 0:09 ` [PATCH 2/5] clk: sunxi-ng: generalise update bit Andre Przywara
2025-09-03 0:09 ` [PATCH 3/5] clk: sunxi-ng: mp: support clocks with just a shift register Andre Przywara
2025-09-03 4:20 ` Chen-Yu Tsai
2025-09-03 10:20 ` Andre Przywara
2025-09-03 0:09 ` [PATCH 4/5] clk: sunxi-ng: add support for the A523/T527 CPU CCU Andre Przywara
2025-09-03 10:26 ` Krzysztof Kozlowski
2025-09-03 0:09 ` [PATCH 5/5] arm64: dts: allwinner: a523: add CPU clocks Andre Przywara
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).