Skip to contentSkip to conversation

clk: sunxi-ng: Add support for Allwinner A733 CCU and PRCM

PATCH In review Junhui Liu 6 participants 25 messages Oct 9 – Nov 11

Subsystems (7)
lore
Share & tools
lore

Junhui Liu

author
#0 lore raw

v6 cover clk: sunxi-ng: Add support for Allwinner A733 CCU and PRCM

Add support for the main CCU and the PRCM module (R-CCU) found in the Allwinner A733 SoC. The clock architecture is derived from the previous A523 design, with the MCU_CCU removed and the clock tree extended for the additional functional blocks found on the A733.

The A733 introduces a "pll-ref" clock that normalizes the physical oscillator frequency, which can be 19.2MHz, 24MHz, or 26MHz, into a consistent 24MHz reference for the PLL clock tree.

The peripheral, video, and DE PLLs provide multiple independently gated outputs with programmable dividers. Model these outputs as separate divider-and-gate child clocks. Also follow the documented hierarchy for the derived peripheral PLL outputs. The explicitly named PLL_AUDIO1 /2 and /5 outputs are modeled as fixed-factor clocks, with their divider fields initialized accordingly.

Also extend the sunxi-ng SDM (Sigma-Delta Modulation) support for the dual-pattern register layout used by the A733 PLLs. PLL_AUDIO0 uses the dual-pattern SDM support to synthesize its fractional output. PLL_AUDIO1 does not expose fractional rates, but its SDM controls are modeled so that stale settings left by firmware can be disabled when an integer rate is programmed.

The actual parents of a small number of bus gates are not documented in the user manual. Follow the vendor BSP and keep these gates parented to "hosc" until more complete hardware information is available.

This series depends on the A523 single-divider clock fixes [1], which add feature support to the M-only clock macro used by the MBUS and DRAM0 clocks. The prerequisite series has been applied to the sunxi/clk-for-7.4 branch.

---
Changes in v6:
- Patches 1 and 3: Drop the R-TWD bus clock, since S_TWD_BGR_REG is
always secure and cannot be accessed by the non-secure kernel
- Patches 1 and 7: Rename mbus-nand and CLK_MBUS_NAND to mbus-nand0 and CLK_MBUS_NAND0
- Patches 3 and 4: Document the firmware requirements for the PRCM and CCMU security switch registers
- Patch 4: Add CLK_SET_RATE_PARENT to the video and DE PLL output clocks
- Patch 5: Document why the CPU_PERI and NSI clocks are not modelled
- Patch 7: Model ahb-store as the parent of the NAND, MMC, SPI, SPIF and UFS bus gates, and drop its CLK_IS_CRITICAL flag
- Patch 7: Keep mbus-store critical for the storage DMA paths and make it the parent of mbus-nand0
- Patch 7: Add comments explaining the ahb-store, ahb-cpus and mbus-store gates
- Patches 5, 7 and 8: Collect Reviewed-by tags
- Link to v5: https://patch.msgid.link/[email protected]

Changes in v5:
- Add the CLK_GIC binding ID, inserted after CLK_TRACE
- Add the GIC clock and mark it critical
- Fix the continuation line alignment of the trace clock
- Mark ahb-cpus critical
- Link to v4: https://patch.msgid.link/[email protected]

Changes in v4:
- Model the MBUS and DRAM0 clocks as M-only clocks
- Base the series on the A523 single-divider clock fixes
- Link to v3: https://patch.msgid.link/[email protected]

Changes in v3:
- Patch 1: Rename the clock/reset binding headers with the allwinner vendor prefix, use BSD-2-Clause for their dual license, and reorder the binding properties according to the preferred schema layout
- Patches 1 and 4: Drop the undocumented 12X suffix from the video and DE PLL core clock names and binding IDs
- Patch 2: Require all PAT1 enable bits to be set when checking whether SDM is enabled
- Patch 4: Model the independently gated peripheral, video, and DE PLL outputs as programmable-divider child clocks
- Patch 4: Follow the documented hierarchy for the derived peripheral PLL outputs
- Patch 4: Model the explicitly named PLL_AUDIO1 /2 and /5 outputs as fixed-factor clocks and initialize their divider fields accordingly
- Patch 4: Model the PLL_AUDIO1 SDM controls so stale firmware settings are disabled when an integer rate is programmed
- Patch 4: Add the missing module device table and remove an unused include
- Patch 6: Replace the MP helpers used by timer clocks, which have no M divider, with the corresponding P-only helpers
- Patch 7: Document the unresolved parents of bus gates kept on hosc and fix the APB/AHB IOMMU1 system clock names
- Patches 3 and 8: Make the reset maps const
- Link to v2: https://patch.msgid.link/[email protected]

Changes in v2:
- Rework the clocks property in DT bindings to source hosc directly from the oscillator to adapt to the new RTC binding
- Clean up the SDM dual-pattern helper macro and add the missing enable parameter for pll-audio0
- Number single-instance clocks with 0, e.g. GPU0, VE_ENC0/VE_DEC0,
DRAM0, NAND0, GPADC0, THS0, etc
- Correct 8x PLL post-divider names to 12x for video and DE PLLs (pll-videoX-12x, pll-de-12x)
- Drop gic, cpu-peri, nsi clocks
- Rename clocks: OWA -> SPDIF, USB_REF -> USB01_REF, HDMI_ESM -> HDCP_ESM, PWMCTRL -> PWM
- Mark bus-dram0, ahb-store and mbus-store critical to avoid DMA, MMC and SPI NOR failures when unused clocks are disabled
- Switch PRCM timer clocks to P-only helpers
- Fix bus gate bit positions for UARTs and correct the sysdap register address
- Interleave bus clocks into function clocks
- Link to v1: https://lore.kernel.org/r/[email protected]

---
Junhui Liu (8):
dt-bindings: clk: sun60i-a733-ccu: Add Allwinner A733 support
clk: sunxi-ng: sdm: Add dual patterns support
clk: sunxi-ng: a733: Add PRCM CCU
clk: sunxi-ng: a733: Add PLL clocks support
clk: sunxi-ng: a733: Add bus clocks support
clk: sunxi-ng: a733: Add mod clocks support
clk: sunxi-ng: a733: Add bus clock gates
clk: sunxi-ng: a733: Add reset lines

 .../bindings/clock/allwinner,sun60i-a733-ccu.yaml  |  107 +
 drivers/clk/sunxi-ng/Kconfig                       |   10 +
 drivers/clk/sunxi-ng/Makefile                      |    4 +
 drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c           |  277 +++
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c             | 2422 ++++++++++++++++++++
 drivers/clk/sunxi-ng/ccu_sdm.c                     |   52 +-
 drivers/clk/sunxi-ng/ccu_sdm.h                     |   29 +-
 .../dt-bindings/clock/allwinner,sun60i-a733-ccu.h  |  291 +++
 .../clock/allwinner,sun60i-a733-r-ccu.h            |   38 +
 .../dt-bindings/reset/allwinner,sun60i-a733-ccu.h  |  129 ++
 .../reset/allwinner,sun60i-a733-r-ccu.h            |   23 +
 11 files changed, 3356 insertions(+), 26 deletions(-)

---
base-commit: e5e04726cdd043e309677071ab1b65a4b18f422b
change-id: 20260202-a733-clk-0d4fc00a9f9c
prerequisite-message-id: <[email protected]>
prerequisite-patch-id: 0df2ae41836b86fd868dfa01ddfde57f888f761a
prerequisite-patch-id: 88f3a431e7c551a9fa732f062188f10fdd362eeb
prerequisite-patch-id: 3e88bc873c909059d1199f82cda4013765e7a5e5
prerequisite-patch-id: 0dbc27cd7417352319a0705a051dff35085e8922

Best regards,

Signature · 1 line
Junhui Liu <[email protected]>
author
#1 lore raw

PATCH v6 1/8 dt-bindings: clk: sun60i-a733-ccu: Add Allwinner A733 support

The CCU and R-CCU (PRCM) modules provide clocks and reset functions for the Allwinner A733 SoC. The clock architecture of the A733 is evolved from the A523, though the root clocking strategy transitions from a static oscillator frequency in the Devicetree to the "hosc" clock, which is determined by choosing from three possible frequencies (19.2MHz, 24MHz, or 26MHz) by the RTC hardware, and finally feeds the CCU and R-CCU.

Additionally, the MCU_CCU module found in previous designs is removed from the A733, and the clock tree is expanded with more clock outputs to support new functional modules.

---
 .../bindings/clock/allwinner,sun60i-a733-ccu.yaml  | 107 ++++++++
 .../dt-bindings/clock/allwinner,sun60i-a733-ccu.h  | 291 +++++++++++++++++++++
 .../clock/allwinner,sun60i-a733-r-ccu.h            |  38 +++
 .../dt-bindings/reset/allwinner,sun60i-a733-ccu.h  | 129 +++++++++
 .../reset/allwinner,sun60i-a733-r-ccu.h            |  23 ++
 5 files changed, 588 insertions(+)
Documentation/devicetree/bindings/clock/allwinner,sun60i-a733-ccu.yaml new file +107 -0
new file mode 100644
index 000000000000..7c9068d3bbb0
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/allwinner,sun60i-a733-ccu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A733 Clock Control Unit
+
+maintainers:
+  - Junhui Liu <[email protected]>
+
+properties:
+  compatible:
+    enum:
+      - allwinner,sun60i-a733-ccu
+      - allwinner,sun60i-a733-r-ccu
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 4
+    maxItems: 7
+
+  clock-names:
+    minItems: 4
+    maxItems: 7
+
+  "#clock-cells":
+    const: 1
+
+  "#reset-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - "#clock-cells"
+  - "#reset-cells"
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - allwinner,sun60i-a733-ccu
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: High Frequency Oscillator (19.2MHz, 24MHz, or 26MHz)
+            - description: Low Frequency Oscillator (usually at 32kHz)
+            - description: Internal Oscillator
+            - description: Low Frequency Oscillator fanout
+
+        clock-names:
+          items:
+            - const: hosc
+            - const: losc
+            - const: iosc
+            - const: losc-fanout
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - allwinner,sun60i-a733-r-ccu
+
+    then:
+      properties:
+        clocks:
+          items:
+            - description: High Frequency Oscillator (19.2MHz, 24MHz, or 26MHz)
+            - description: Low Frequency Oscillator (usually at 32kHz)
+            - description: Internal Oscillator
+            - description: System 24MHz Clock
+            - description: Peripherals PLL 0 (200 MHz output)
+            - description: Peripherals PLL 0 (300 MHz output)
+            - description: Peripherals PLL 1 (300 MHz output)
+
+        clock-names:
+          items:
+            - const: hosc
+            - const: losc
+            - const: iosc
+            - const: sys-24m
+            - const: pll-periph0-200m
+            - const: pll-periph0-300m
+            - const: pll-periph1-300m
+
+additionalProperties: false
+
+examples:
+  - |
+    clock-controller@2002000 {
+      compatible = "allwinner,sun60i-a733-ccu";
+      reg = <0x02002000 0x2000>;
+      clocks = <&osc>, <&rtc 0>, <&rtc 2>, <&rtc 1>;
+      clock-names = "hosc", "losc", "iosc", "losc-fanout";
+      #clock-cells = <1>;
+      #reset-cells = <1>;
+    };
+
+...
include/dt-bindings/clock/allwinner,sun60i-a733-ccu.h new file +291 -0

291 lines not on this page · raw message

include/dt-bindings/clock/allwinner,sun60i-a733-r-ccu.h new file +38 -0
new file mode 100644
index 000000000000..401a1e66e804
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_CLK_ALLWINNER_SUN60I_A733_R_CCU_H_
+#define _DT_BINDINGS_CLK_ALLWINNER_SUN60I_A733_R_CCU_H_
+
+#define CLK_R_AHB		0
+#define CLK_R_APB0		1
+#define CLK_R_APB1		2
+#define CLK_R_TIMER0		3
+#define CLK_R_TIMER1		4
+#define CLK_R_TIMER2		5
+#define CLK_R_TIMER3		6
+#define CLK_BUS_R_TIMER		7
+#define CLK_R_PWM		8
+#define CLK_BUS_R_PWM		9
+#define CLK_R_SPI		10
+#define CLK_BUS_R_SPI		11
+#define CLK_BUS_R_MSGBOX	12
+#define CLK_BUS_R_UART0		13
+#define CLK_BUS_R_UART1		14
+#define CLK_BUS_R_I2C0		15
+#define CLK_BUS_R_I2C1		16
+#define CLK_BUS_R_I2C2		17
+#define CLK_BUS_R_PPU		18
+#define CLK_BUS_R_TZMA		19
+#define CLK_BUS_R_CPU_BIST	20
+#define CLK_R_IR_RX		21
+#define CLK_BUS_R_IR_RX		22
+#define CLK_BUS_R_RTC		23
+#define CLK_R_RISCV		24
+#define CLK_BUS_R_RISCV		25
+#define CLK_BUS_R_RISCV_CFG	26
+#define CLK_BUS_R_CPUCFG	27
+
+#endif /* _DT_BINDINGS_CLK_ALLWINNER_SUN60I_A733_R_CCU_H_ */
include/dt-bindings/reset/allwinner,sun60i-a733-ccu.h new file +129 -0

129 lines not on this page · raw message

include/dt-bindings/reset/allwinner,sun60i-a733-r-ccu.h new file +23 -0
new file mode 100644
index 000000000000..69fc7d405e1d
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 Junhui Liu <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_RST_ALLWINNER_SUN60I_A733_R_CCU_H_
+#define _DT_BINDINGS_RST_ALLWINNER_SUN60I_A733_R_CCU_H_
+
+#define RST_BUS_R_TIMER		0
+#define RST_BUS_R_PWM		1
+#define RST_BUS_R_SPI		2
+#define RST_BUS_R_MSGBOX	3
+#define RST_BUS_R_UART0		4
+#define RST_BUS_R_UART1		5
+#define RST_BUS_R_I2C0		6
+#define RST_BUS_R_I2C1		7
+#define RST_BUS_R_I2C2		8
+#define RST_BUS_R_IR_RX		9
+#define RST_BUS_R_RTC		10
+#define RST_BUS_R_RISCV_CFG	11
+#define RST_BUS_R_CPUCFG	12
+
+#endif /* _DT_BINDINGS_RST_ALLWINNER_SUN60I_A733_R_CCU_H_ */
Signature · 1 line
2.55.0
author
#2 lore raw

PATCH v6 2/8 clk: sunxi-ng: sdm: Add dual patterns support

In reply to Junhui Liu

On newer Allwinner platforms like the A733, the Sigma-Delta Modulation (SDM) control logic is more complex. The SDM enable bit, which was previously located in the PLL register, is now moved to a second pattern register (PATTERN1).

To support this, rename the existing "tuning" members to "pattern0" to align with the datasheet, and introduce the _SUNXI_CCU_SDM_DUAL_PAT macro to provide pattern1 register support. Related operations are also updated.

---
 drivers/clk/sunxi-ng/ccu_sdm.c | 52 ++++++++++++++++++++++++++++++------------
 drivers/clk/sunxi-ng/ccu_sdm.h | 29 ++++++++++++++---------
 2 files changed, 55 insertions(+), 26 deletions(-)
drivers/clk/sunxi-ng/ccu_sdm.c +37 -15
index c564e5f9e610..7e13ffd246d3 100644
@@ -18,7 +18,11 @@ bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
 	if (sdm->enable && !(readl(common->base + common->reg) & sdm->enable))
 		return false;
 
-	return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable);
+	if (sdm->pat1_enable &&
+	    (readl(common->base + sdm->pat1_reg) & sdm->pat1_enable) != sdm->pat1_enable)
+		return false;
+
+	return !!(readl(common->base + sdm->pat0_reg) & sdm->pat0_enable);
 }
 EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, "SUNXI_CCU");
 
@@ -37,18 +41,27 @@ void ccu_sdm_helper_enable(struct ccu_common *common,
 	for (i = 0; i < sdm->table_size; i++)
 		if (sdm->table[i].rate == rate)
 			writel(sdm->table[i].pattern,
-			       common->base + sdm->tuning_reg);
+			       common->base + sdm->pat0_reg);
 
 	/* Make sure SDM is enabled */
 	spin_lock_irqsave(common->lock, flags);
-	reg = readl(common->base + sdm->tuning_reg);
-	writel(reg | sdm->tuning_enable, common->base + sdm->tuning_reg);
+	reg = readl(common->base + sdm->pat0_reg);
+	writel(reg | sdm->pat0_enable, common->base + sdm->pat0_reg);
 	spin_unlock_irqrestore(common->lock, flags);
 
-	spin_lock_irqsave(common->lock, flags);
-	reg = readl(common->base + common->reg);
-	writel(reg | sdm->enable, common->base + common->reg);
-	spin_unlock_irqrestore(common->lock, flags);
+	if (sdm->enable) {
+		spin_lock_irqsave(common->lock, flags);
+		reg = readl(common->base + common->reg);
+		writel(reg | sdm->enable, common->base + common->reg);
+		spin_unlock_irqrestore(common->lock, flags);
+	}
+
+	if (sdm->pat1_enable) {
+		spin_lock_irqsave(common->lock, flags);
+		reg = readl(common->base + sdm->pat1_reg);
+		writel(reg | sdm->pat1_enable, common->base + sdm->pat1_reg);
+		spin_unlock_irqrestore(common->lock, flags);
+	}
 }
 EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, "SUNXI_CCU");
 
@@ -61,14 +74,23 @@ void ccu_sdm_helper_disable(struct ccu_common *common,
 	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
 		return;
 
-	spin_lock_irqsave(common->lock, flags);
-	reg = readl(common->base + common->reg);
-	writel(reg & ~sdm->enable, common->base + common->reg);
-	spin_unlock_irqrestore(common->lock, flags);
+	if (sdm->enable) {
+		spin_lock_irqsave(common->lock, flags);
+		reg = readl(common->base + common->reg);
+		writel(reg & ~sdm->enable, common->base + common->reg);
+		spin_unlock_irqrestore(common->lock, flags);
+	}
+
+	if (sdm->pat1_enable) {
+		spin_lock_irqsave(common->lock, flags);
+		reg = readl(common->base + sdm->pat1_reg);
+		writel(reg & ~sdm->pat1_enable, common->base + sdm->pat1_reg);
+		spin_unlock_irqrestore(common->lock, flags);
+	}
 
 	spin_lock_irqsave(common->lock, flags);
-	reg = readl(common->base + sdm->tuning_reg);
-	writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg);
+	reg = readl(common->base + sdm->pat0_reg);
+	writel(reg & ~sdm->pat0_enable, common->base + sdm->pat0_reg);
 	spin_unlock_irqrestore(common->lock, flags);
 }
 EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, "SUNXI_CCU");
@@ -123,7 +145,7 @@ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
 	pr_debug("%s: clock is sigma-delta modulated\n",
 		 clk_hw_get_name(&common->hw));
 
-	reg = readl(common->base + sdm->tuning_reg);
+	reg = readl(common->base + sdm->pat0_reg);
 
 	pr_debug("%s: pattern reg is 0x%x",
 		 clk_hw_get_name(&common->hw), reg);
drivers/clk/sunxi-ng/ccu_sdm.h +18 -11
index c1a7159b89c3..e94cef141c7d 100644
@@ -33,21 +33,28 @@ struct ccu_sdm_internal {
 	u32		table_size;
 	/* early SoCs don't have the SDM enable bit in the PLL register */
 	u32		enable;
-	/* second enable bit in tuning register */
-	u32		tuning_enable;
-	u16		tuning_reg;
+	/* second enable bit in pattern0 register */
+	u32		pat0_enable;
+	u16		pat0_reg;
+	/* on some platforms, the sdm enable bit in pattern1 register */
+	u32		pat1_enable;
+	u16		pat1_reg;
 };
 
-#define _SUNXI_CCU_SDM(_table, _enable,			\
-		       _reg, _reg_enable)		\
-	{						\
-		.table		= _table,		\
-		.table_size	= ARRAY_SIZE(_table),	\
-		.enable		= _enable,		\
-		.tuning_enable	= _reg_enable,		\
-		.tuning_reg	= _reg,			\
+#define _SUNXI_CCU_SDM_DUAL_PAT(_table, _enable, _pat0, _pat0_enable, _pat1, _pat1_enable) \
+	{								\
+		.table			= _table,			\
+		.table_size		= ARRAY_SIZE(_table),		\
+		.enable			= _enable,			\
+		.pat0_enable		= _pat0_enable,			\
+		.pat0_reg		= _pat0,			\
+		.pat1_enable		= _pat1_enable,			\
+		.pat1_reg		= _pat1,			\
 	}
 
+#define _SUNXI_CCU_SDM(_table, _enable, _pat0, _pat0_enable)	\
+	_SUNXI_CCU_SDM_DUAL_PAT(_table, _enable, _pat0, _pat0_enable, 0, 0)
+
 bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
 			       struct ccu_sdm_internal *sdm);
 void ccu_sdm_helper_enable(struct ccu_common *common,
Signature · 1 line
2.55.0
author
#3 lore raw

PATCH v6 3/8 clk: sunxi-ng: a733: Add PRCM CCU

In reply to Junhui Liu

Add support for the Power Reset Clock Management (PRCM) module found in the Allwinner A733 SoC. This clock controller manages the clock control and reset functions for device modules within the CPUS domain.

The PRCM module includes the management of three primary buses: r-ahb, r-apb0, and r-apb1. It also provides clocking for several key peripherals, such as R-UART, R-I2C, R-SPI, and the R-RISCV subsystem. Additionally, the reset lines for these modules are integrated.

---
 drivers/clk/sunxi-ng/Kconfig             |   5 +
 drivers/clk/sunxi-ng/Makefile            |   2 +
 drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c | 277 +++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+)
drivers/clk/sunxi-ng/Kconfig +5 -0
index 6af2d020e03e..202e793dc754 100644
@@ -67,6 +67,11 @@ config SUN55I_A523_R_CCU
 	default ARCH_SUNXI
 	depends on ARM64 || COMPILE_TEST
 
+config SUN60I_A733_R_CCU
+	tristate "Support for the Allwinner A733 PRCM CCU"
+	default ARCH_SUNXI
+	depends on ARM64 || COMPILE_TEST
+
 config SUN4I_A10_CCU
 	tristate "Support for the Allwinner A10/A20 CCU"
 	default ARCH_SUNXI
drivers/clk/sunxi-ng/Makefile +2 -0
index a1c4087d7241..d3702bdb7a23 100644
@@ -36,6 +36,7 @@ obj-$(CONFIG_SUN50I_H616_CCU)	+= sun50i-h616-ccu.o
 obj-$(CONFIG_SUN55I_A523_CCU)	+= sun55i-a523-ccu.o
 obj-$(CONFIG_SUN55I_A523_MCU_CCU)	+= sun55i-a523-mcu-ccu.o
 obj-$(CONFIG_SUN55I_A523_R_CCU)	+= sun55i-a523-r-ccu.o
+obj-$(CONFIG_SUN60I_A733_R_CCU)	+= sun60i-a733-r-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
@@ -64,6 +65,7 @@ sun50i-h616-ccu-y		+= ccu-sun50i-h616.o
 sun55i-a523-ccu-y		+= ccu-sun55i-a523.o
 sun55i-a523-mcu-ccu-y		+= ccu-sun55i-a523-mcu.o
 sun55i-a523-r-ccu-y		+= ccu-sun55i-a523-r.o
+sun60i-a733-r-ccu-y		+= ccu-sun60i-a733-r.o
 sun4i-a10-ccu-y			+= ccu-sun4i-a10.o
 sun5i-ccu-y			+= ccu-sun5i.o
 sun6i-a31-ccu-y			+= ccu-sun6i-a31.o
drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c new file +277 -0

277 lines not on this page · raw message

Signature · 1 line
2.55.0
#4 lore raw

Re: [PATCH v6 3/8] clk: sunxi-ng: a733: Add PRCM CCU

Hi Junhui,

drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c line 64

Quoted 5 lines · Junhui Liu
drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c new file +5 -0
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(r_cpu_timer0, "r-timer0", r_apb_parents, 0x100,
+				      1, 3,	/* P */
+				      4, 3,	/* mux */
+				      BIT(0),	/* gate */
+				      0);

On a Cubie A7S with vendor boot firmware, v6 reaches a Linux shell but stalls at warm reboot. The system-controller firmware uses the R-domain timer and mailboxes without Linux clock consumers, so disabling these clocks as unused can leave its services unavailable.

Could you consider marking r-timer0, bus-r-timer, bus-r-riscv and bus-r-msgbox here, and bus-msgbox0 in 7/8, CLK_IS_CRITICAL in the next revision? My standalone patch has the diff, firmware references and board results:
https://lore.kernel.org/r/[email protected]

With those five flags, two RAM boots of my A7S integration completed warm reboots without clk_ignore_unused, and all five clocks reported enabled. That is one board on vendor firmware. Vinicius reported native PSCI reboot working on an A7Z without local critical flags on bus-r-riscv and bus-r-msgbox, with TF-A and U-Boot built from source, so the boot chain may matter. I haven't tested suspend, or shown that each of the five flags is needed on its own.

Thanks,
Enzo

author
#5 lore raw

Re: [PATCH v6 3/8] clk: sunxi-ng: a733: Add PRCM CCU

Hi Enzo,

Quoted 14 lines · Enzo Adriano

Hi Junhui,

drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c line 64

Quoted 5 lines · Junhui Liu
drivers/clk/sunxi-ng/ccu-sun60i-a733-r.c new file +5 -0
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(r_cpu_timer0, "r-timer0", r_apb_parents, 0x100,
+				      1, 3,	/* P */
+				      4, 3,	/* mux */
+				      BIT(0),	/* gate */
+				      0);

On a Cubie A7S with vendor boot firmware, v6 reaches a Linux shell but stalls at warm reboot. The system-controller firmware uses the R-domain timer and mailboxes without Linux clock consumers, so disabling these clocks as unused can leave its services unavailable.

Quoted 5 lines

Could you consider marking r-timer0, bus-r-timer, bus-r-riscv and bus-r-msgbox here, and bus-msgbox0 in 7/8, CLK_IS_CRITICAL in the next revision? My standalone patch has the diff, firmware references and board results:
https://lore.kernel.org/r/[email protected]

I'd prefer not to mark these clocks as critical just for the vendor firmware. You can see my reply in v5:

https://lore.kernel.org/linux-sunxi/[email protected]/

Since you've already submitted a separate patch adding these critical flags, I'll leave that to you. If the maintainers agree that these clocks should be marked critical, your patch can be picked up.

Quoted 11 lines

With those five flags, two RAM boots of my A7S integration completed warm reboots without clk_ignore_unused, and all five clocks reported enabled. That is one board on vendor firmware. Vinicius reported native PSCI reboot working on an A7Z without local critical flags on bus-r-riscv and bus-r-msgbox, with TF-A and U-Boot built from source, so the boot chain may matter. I haven't tested suspend, or shown that each of the five flags is needed on its own.

Thanks,
Enzo

Signature · 2 lines
Best regards,
Junhui Liu
#6 lore raw

Re: [PATCH v6 3/8] clk: sunxi-ng: a733: Add PRCM CCU

Hi Junhui,

Quoted 2 lines

I'd prefer not to mark these clocks as critical just for the vendor firmware. You can see my reply in v5:

I agree that native PSCI and a future OR100 Crust port are separate from the vendor SCP on E902, and that future E902 remoteproc/mailbox drivers should own these clocks. Vinicius's native-PSCI reboot report used locally modified TF-A on A7Z [1]. Upstream TF-A still has no A733 target; its port is under review [2]. The immediate problem is that the new CCU's unused-clock cleanup breaks reboot with the firmware these boards ship.

On one Cubie A7S, RAM-booting v7.4-rc1 + CCU v6 + DT v3 and its dependencies with vendor boot0/BL31/SCP/U-Boot and no clk_ignore_unused, the run without critical flags stalled at reboot -f. With only bus-r-riscv and bus-r-msgbox critical, two warm reboots returned to vendor Linux while r-timer0, bus-r-timer and bus-msgbox0 were 0/0 (enable/prepare); five flags also passed once.

Quoted 2 lines

Since you've already submitted a separate patch adding these critical flags, I'll leave that to you.

I will narrow my separate patch [3] to bus-r-riscv and bus-r-msgbox. Chen-Yu, Jernej, Samuel: would you take these two flags as a separate patch until E902/mailbox drivers can own the clocks? There is precedent in A523 bus-r-cpucfg (1dba74abf3e2) and Meson AXG fclk_div3, kept critical for SCPI firmware until the driver claims its clocks and a handoff exists (drivers/clk/meson/axg.c).

I have not tested power-off, suspend, either flag alone on A7S, or other boards or firmware; Vinicius found either flag alone insufficient on A7Z with vendor BL31 [4].

[1] https://lore.kernel.org/r/[email protected]
[2] https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/55200
[3] https://lore.kernel.org/r/[email protected]
[4] https://lore.kernel.org/r/[email protected]

Thanks,
Enzo

author
#7 lore raw

PATCH v6 4/8 clk: sunxi-ng: a733: Add PLL clocks support

In reply to Junhui Liu

Add PLL clock support for the main CCU of the Allwinner A733 SoC. The structure is mostly similar to the sun55i, with the addition of a PLL_REF clock that normalizes the hardware-detected DCXO/hosc frequency (19.2MHz, 24MHz, or 26MHz) into a consistent 24MHz reference for all subsequent PLLs.

Model the independently gated outputs of the peripheral, video, and DE PLLs as programmable-divider child clocks, with each output gate modeled separately. Follow the documented hierarchy for the derived peripheral PLL outputs.

PLL_AUDIO0 uses SDM parameters from the vendor driver to provide a 22.5792MHz * 4 output. PLL_AUDIO1 provides fixed /2 and /5 outputs and does not expose fractional rates, but its SDM controls are modeled so that stale firmware settings can be disabled when an integer rate is programmed.

---
 drivers/clk/sunxi-ng/Kconfig           |   5 +
 drivers/clk/sunxi-ng/Makefile          |   2 +
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 586 +++++++++++++++++++++++++++++++++
 3 files changed, 593 insertions(+)
drivers/clk/sunxi-ng/Kconfig +5 -0
index 202e793dc754..cffa83056934 100644
@@ -67,6 +67,11 @@ config SUN55I_A523_R_CCU
 	default ARCH_SUNXI
 	depends on ARM64 || COMPILE_TEST
 
+config SUN60I_A733_CCU
+	tristate "Support for the Allwinner A733 CCU"
+	default ARCH_SUNXI
+	depends on ARM64 || COMPILE_TEST
+
 config SUN60I_A733_R_CCU
 	tristate "Support for the Allwinner A733 PRCM CCU"
 	default ARCH_SUNXI
drivers/clk/sunxi-ng/Makefile +2 -0
index d3702bdb7a23..3a39eb9287da 100644
@@ -36,6 +36,7 @@ obj-$(CONFIG_SUN50I_H616_CCU)	+= sun50i-h616-ccu.o
 obj-$(CONFIG_SUN55I_A523_CCU)	+= sun55i-a523-ccu.o
 obj-$(CONFIG_SUN55I_A523_MCU_CCU)	+= sun55i-a523-mcu-ccu.o
 obj-$(CONFIG_SUN55I_A523_R_CCU)	+= sun55i-a523-r-ccu.o
+obj-$(CONFIG_SUN60I_A733_CCU)	+= sun60i-a733-ccu.o
 obj-$(CONFIG_SUN60I_A733_R_CCU)	+= sun60i-a733-r-ccu.o
 obj-$(CONFIG_SUN4I_A10_CCU)	+= sun4i-a10-ccu.o
 obj-$(CONFIG_SUN5I_CCU)		+= sun5i-ccu.o
@@ -65,6 +66,7 @@ sun50i-h616-ccu-y		+= ccu-sun50i-h616.o
 sun55i-a523-ccu-y		+= ccu-sun55i-a523.o
 sun55i-a523-mcu-ccu-y		+= ccu-sun55i-a523-mcu.o
 sun55i-a523-r-ccu-y		+= ccu-sun55i-a523-r.o
+sun60i-a733-ccu-y		+= ccu-sun60i-a733.o
 sun60i-a733-r-ccu-y		+= ccu-sun60i-a733-r.o
 sun4i-a10-ccu-y			+= ccu-sun4i-a10.o
 sun5i-ccu-y			+= ccu-sun5i.o
drivers/clk/sunxi-ng/ccu-sun60i-a733.c new file +586 -0

586 lines not on this page · raw message

Signature · 1 line
2.55.0
maintainer Reviewed-by on v6 4/8
#8 lore raw

Re: [PATCH v6 4/8] clk: sunxi-ng: a733: Add PLL clocks support

Quoted 12 lines · Junhui Liu

Add PLL clock support for the main CCU of the Allwinner A733 SoC. The structure is mostly similar to the sun55i, with the addition of a PLL_REF clock that normalizes the hardware-detected DCXO/hosc frequency (19.2MHz, 24MHz, or 26MHz) into a consistent 24MHz reference for all subsequent PLLs.

Model the independently gated outputs of the peripheral, video, and DE PLLs as programmable-divider child clocks, with each output gate modeled separately. Follow the documented hierarchy for the derived peripheral PLL outputs.

Quoted 8 lines

PLL_AUDIO0 uses SDM parameters from the vendor driver to provide a 22.5792MHz * 4 output. PLL_AUDIO1 provides fixed /2 and /5 outputs and does not expose fractional rates, but its SDM controls are modeled so that stale firmware settings can be disabled when an integer rate is programmed.

author
#9 lore raw

PATCH v6 5/8 clk: sunxi-ng: a733: Add bus clocks support

In reply to Junhui Liu

Add the essential bus clocks in the Allwinner A733 CCU, including AHB, APB0, APB1, APB_UART, and MBUS. These buses are necessary for many other functional modules. Additional clocks such as trace and gic are also added as they fall within the register address range of the bus clocks, even though they are not strictly bus clocks.

The MBUS clock is marked as critical to ensure the memory bus remains operational at all times. And the hardware requires an update bit (bit 27) to be set so that the configuration takes effect and the updated parameters can be correctly read back for the MBUS clock.

The GIC clock is also marked as critical. The bootloader may leave the GIC running on a PLL parent, and disabling that PLL during clk_disable_unused would hang the interrupt controller and the system.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 108 +++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +108 -0
index 3368801053ec..371c4297c3ab 100644
@@ -8,6 +8,9 @@
  * When secure boot is enabled, firmware must configure CCMU_SEC_SWITCH_REG
  * to make the PLL, bus and MBUS clock registers accessible to the
  * non-secure world.
+ *
+ * CPU_PERI_CLK_REG has no documented consumer, while NSI_CLK_REG has no
+ * known kernel consumer, so they are not modelled here.
  */
 
 #include <linux/clk-provider.h>
@@ -22,6 +25,7 @@
 
 #include "ccu_div.h"
 #include "ccu_gate.h"
+#include "ccu_mp.h"
 #include "ccu_mult.h"
 #include "ccu_nkmp.h"
 #include "ccu_nm.h"
@@ -72,6 +76,16 @@ static const struct clk_hw *pll_ref_hws[] = {
 	&pll_ref_clk.common.hw
 };
 
+/*
+ * There is a non-software-configurable mux selecting between the DCXO and the
+ * PLL_REF in hardware, whose output is fed to the sys-24M clock. Although both
+ * sys-24M and pll-ref are fixed at 24 MHz, define a 1:1 fixed factor clock to
+ * provide logical separation:
+ * - pll-ref is dedicated to feeding other PLLs
+ * - sys-24M serves as reference clock for downstream functional modules
+ */
+static CLK_FIXED_FACTOR_HWS(sys_24M_clk, "sys-24M", pll_ref_hws, 1, 1, 0);
+
 #define SUN60I_A733_PLL_DDR_REG		0x020
 static struct ccu_nkmp pll_ddr_clk = {
 	.enable		= BIT(27),
@@ -418,6 +432,85 @@ static SUNXI_CCU_M_HWS_WITH_GATE(pll_de_3x_clk, "pll-de-3x", pll_de_hws,
 				 SUN60I_A733_PLL_DE_REG,
 				 16, 3, BIT(26), CLK_SET_RATE_PARENT);
 
+/**************************************************************************
+ *                           bus clocks                                   *
+ **************************************************************************/
+
+static const struct clk_parent_data ahb_apb_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_600M_clk.hw },
+};
+
+static SUNXI_CCU_M_DATA_WITH_MUX(ahb_clk, "ahb", ahb_apb_parents, 0x500,
+				 0, 5,		/* M */
+				 24, 2,		/* mux */
+				 0);
+
+static SUNXI_CCU_M_DATA_WITH_MUX(apb0_clk, "apb0", ahb_apb_parents, 0x510,
+				 0, 5,		/* M */
+				 24, 2,		/* mux */
+				 0);
+
+static SUNXI_CCU_M_DATA_WITH_MUX(apb1_clk, "apb1", ahb_apb_parents, 0x518,
+				 0, 5,		/* M */
+				 24, 2,		/* mux */
+				 0);
+
+static const struct clk_parent_data apb_uart_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX(apb_uart_clk, "apb-uart", apb_uart_parents, 0x538,
+				 0, 5,		/* M */
+				 24, 3,		/* mux */
+				 0);
+
+static const struct clk_parent_data trace_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .hw = &pll_periph0_400M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(trace_clk, "trace", trace_parents, 0x540,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data gic_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph0_400M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gic_clk, "gic", gic_parents, 0x560,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      CLK_IS_CRITICAL);
+
+static const struct clk_parent_data mbus_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph1_600M_clk.hw },
+	{ .hw = &pll_ddr_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .hw = &pll_periph1_400M_clk.hw },
+	{ .hw = &pll_npu_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588,
+					   0, 5,	/* M */
+					   24, 3,	/* mux */
+					   BIT(31),	/* gate */
+					   CLK_IS_CRITICAL,
+					   CCU_FEATURE_UPDATE_BIT);
+
 /*
  * Contains all clocks that are controlled by a hardware register. They
  * have a (sunxi) .common member, which needs to be initialised by the common
@@ -452,11 +545,19 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
 	&pll_de_clk.common,
 	&pll_de_4x_clk.common,
 	&pll_de_3x_clk.common,
+	&ahb_clk.common,
+	&apb0_clk.common,
+	&apb1_clk.common,
+	&apb_uart_clk.common,
+	&trace_clk.common,
+	&gic_clk.common,
+	&mbus_clk.common,
 };
 
 static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 	.hws	= {
 		[CLK_PLL_REF]		= &pll_ref_clk.common.hw,
+		[CLK_SYS_24M]		= &sys_24M_clk.hw,
 		[CLK_PLL_DDR]		= &pll_ddr_clk.common.hw,
 		[CLK_PLL_PERIPH0_4X]	= &pll_periph0_4x_clk.common.hw,
 		[CLK_PLL_PERIPH0_2X]	= &pll_periph0_2x_clk.common.hw,
@@ -498,6 +599,13 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 		[CLK_PLL_DE]		= &pll_de_clk.common.hw,
 		[CLK_PLL_DE_4X]		= &pll_de_4x_clk.common.hw,
 		[CLK_PLL_DE_3X]		= &pll_de_3x_clk.common.hw,
+		[CLK_AHB]		= &ahb_clk.common.hw,
+		[CLK_APB0]		= &apb0_clk.common.hw,
+		[CLK_APB1]		= &apb1_clk.common.hw,
+		[CLK_APB_UART]		= &apb_uart_clk.common.hw,
+		[CLK_TRACE]		= &trace_clk.common.hw,
+		[CLK_GIC]		= &gic_clk.common.hw,
+		[CLK_MBUS]		= &mbus_clk.common.hw,
 	},
 	.num	= CLK_FANOUT3 + 1,
 };
Signature · 1 line
2.55.0
maintainer
#10 lore raw

Re: [PATCH v6 5/8] clk: sunxi-ng: a733: Add bus clocks support

Quoted 27 lines · Junhui Liu

Add the essential bus clocks in the Allwinner A733 CCU, including AHB, APB0, APB1, APB_UART, and MBUS. These buses are necessary for many other functional modules. Additional clocks such as trace and gic are also added as they fall within the register address range of the bus clocks, even though they are not strictly bus clocks.

The MBUS clock is marked as critical to ensure the memory bus remains operational at all times. And the hardware requires an update bit (bit 27) to be set so that the configuration takes effect and the updated parameters can be correctly read back for the MBUS clock.

The GIC clock is also marked as critical. The bootloader may leave the GIC running on a PLL parent, and disabling that PLL during clk_disable_unused would hang the interrupt controller and the system.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 108 +++++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +0 -0
index 3368801053ec..371c4297c3ab 100644

[...]

Quoted 4 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +4 -0
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gic_clk, "gic", gic_parents, 0x560,
+                                     0, 5,     /* M */
+                                     24, 3,    /* mux */
+                                     BIT(31),  /* gate */

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_HWS_WITH_GATE(pll_de_3x_clk, "pll-de-3x", pll_de_hws, · line 506

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+                                     CLK_IS_CRITICAL);
+
+static const struct clk_parent_data mbus_parents[] = {
+       { .hw = &sys_24M_clk.hw },
+       { .hw = &pll_periph1_600M_clk.hw },
+       { .hw = &pll_ddr_clk.common.hw },
+       { .hw = &pll_periph1_480M_clk.common.hw },
+       { .hw = &pll_periph1_400M_clk.hw },
+       { .hw = &pll_npu_clk.common.hw },
+};

Don't know why I didn't see this earlier, but my LLM agent flagged this.

Based on the manual (1.0) and BSP sources, the periph PLL sources are from periph0, not periph1.

Once fixed, my review stands.

author
#11 lore raw

PATCH v6 6/8 clk: sunxi-ng: a733: Add mod clocks support

In reply to Junhui Liu

Add the module clocks found in the Allwinner A733 SoC, including video, storage, interfaces and others. While most of these clocks are similar to those in the A523 SoC, this implementation accounts for changes in register offsets and introduces support for new modules.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 1103 ++++++++++++++++++++++++++++++++
 1 file changed, 1103 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +1103 -0
index 371c4297c3ab..7847eec84313 100644
@@ -27,6 +27,7 @@
 #include "ccu_gate.h"
 #include "ccu_mp.h"
 #include "ccu_mult.h"
+#include "ccu_mux.h"
 #include "ccu_nkmp.h"
 #include "ccu_nm.h"
 
@@ -85,6 +86,9 @@ static const struct clk_hw *pll_ref_hws[] = {
  * - sys-24M serves as reference clock for downstream functional modules
  */
 static CLK_FIXED_FACTOR_HWS(sys_24M_clk, "sys-24M", pll_ref_hws, 1, 1, 0);
+static const struct clk_hw *sys_24M_hws[] = {
+	&sys_24M_clk.hw
+};
 
 #define SUN60I_A733_PLL_DDR_REG		0x020
 static struct ccu_nkmp pll_ddr_clk = {
@@ -161,6 +165,9 @@ static CLK_FIXED_FACTOR_HWS(pll_periph0_200M_clk, "pll-periph0-200M",
 			    pll_periph0_400M_hws, 2, 1, 0);
 static CLK_FIXED_FACTOR_HWS(pll_periph0_150M_clk, "pll-periph0-150M",
 			    pll_periph0_300M_hws, 2, 1, 0);
+static const struct clk_hw *pll_periph0_150M_hws[] = {
+	&pll_periph0_150M_clk.hw
+};
 static CLK_FIXED_FACTOR_HWS(pll_periph0_160M_clk, "pll-periph0-160M",
 			    pll_periph0_480M_hws, 3, 1, 0);
 
@@ -511,6 +518,912 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588
 					   CLK_IS_CRITICAL,
 					   CCU_FEATURE_UPDATE_BIT);
 
+/**************************************************************************
+ *                          mod clocks                                    *
+ **************************************************************************/
+
+static const struct clk_parent_data timer_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "iosc" },
+	{ .fw_name = "losc" },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer0_clk, "timer0", timer_parents, 0x800,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer1_clk, "timer1", timer_parents, 0x804,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer2_clk, "timer2", timer_parents, 0x808,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer3_clk, "timer3", timer_parents, 0x80c,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer4_clk, "timer4", timer_parents, 0x810,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer5_clk, "timer5", timer_parents, 0x814,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer6_clk, "timer6", timer_parents, 0x818,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer7_clk, "timer7", timer_parents, 0x81c,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer8_clk, "timer8", timer_parents, 0x820,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer9_clk, "timer9", timer_parents, 0x824,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data avs_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(avs_clk, "avs-clk", avs_parents, 0x880,
+				    24, 3,		/* mux */
+				    BIT(31),		/* gate */
+				    0);
+
+static const struct clk_hw *de_parents[] = {
+	&pll_de_3x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(de0_clk, "de0", de_parents, 0xa00,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *di_parents[] = {
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", di_parents, 0xa20,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *g2d_parents[] = {
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", g2d_parents, 0xa40,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *eink_parents[] = {
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(eink_clk, "eink", eink_parents, 0xa60,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *eink_panel_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video0_3x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video1_3x_clk.common.hw,
+	&pll_periph0_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(eink_panel_clk, "eink-panel", eink_panel_parents, 0xa64,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ve_enc_parents[] = {
+	&pll_ve0_clk.common.hw,
+	&pll_ve1_clk.common.hw,
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+	&pll_npu_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_enc0_clk, "ve-enc0", ve_enc_parents, 0xa80,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ve_dec_parents[] = {
+	&pll_ve1_clk.common.hw,
+	&pll_ve0_clk.common.hw,
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+	&pll_npu_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_dec0_clk, "ve-dec0", ve_dec_parents, 0xa88,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ce_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0xac0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *npu_parents[] = {
+	&pll_npu_clk.common.hw,
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_ve0_clk.common.hw,
+	&pll_ve1_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(npu_clk, "npu", npu_parents, 0xb00,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+/*
+ * GPU_CLK = ClockSource * ((16 - M) / 16)
+ * Here we use a div_table to select M values that result in integer divisors.
+ */
+static struct clk_div_table gpu_div_table[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 8, .div = 2 },
+	{ .val = 12, .div = 4 },
+	{ .val = 14, .div = 8 },
+	{ .val = 15, .div = 16 },
+	{ /* sentinel */ },
+};
+static const struct clk_parent_data gpu_parents[] = {
+	{ .hw = &pll_gpu0_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_periph0_400M_clk.hw, },
+	{ .hw = &pll_periph0_300M_clk.hw, },
+	{ .hw = &pll_periph0_200M_clk.hw, },
+};
+static struct ccu_div gpu0_clk = {
+	.enable		= BIT(31),
+	.div		= _SUNXI_CCU_DIV_TABLE(0, 4, gpu_div_table),
+	.mux		= _SUNXI_CCU_MUX(24, 3),
+	.common		= {
+		.reg		= 0xb20,
+		.features	= CCU_FEATURE_UPDATE_BIT,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("gpu0", gpu_parents,
+							   &ccu_div_ops, 0),
+	}
+};
+
+static const struct clk_parent_data dram_parents[] = {
+	{ .hw = &pll_ddr_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_de_clk.common.hw, },
+	{ .hw = &pll_npu_clk.common.hw, },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(dram0_clk, "dram0", dram_parents, 0xc00,
+					   0, 4,	/* M */
+					   24, 3,	/* mux */
+					   BIT(31),	/* gate */
+					   CLK_IS_CRITICAL,
+					   CCU_FEATURE_UPDATE_BIT);
+
+static const struct clk_parent_data nand_mmc_parents[] = {
+	{ .hw = &sys_24M_clk.hw, },
+	{ .hw = &pll_periph0_400M_clk.hw, },
+	{ .hw = &pll_periph0_300M_clk.hw, },
+	{ .hw = &pll_periph1_400M_clk.hw, },
+	{ .hw = &pll_periph1_300M_clk.hw, },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(nand0_clk0_clk, "nand0-clk0", nand_mmc_parents, 0xc80,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(nand0_clk1_clk, "nand0-clk1", nand_mmc_parents, 0xc84,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc0_clk, "mmc0", nand_mmc_parents, 0xd00,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc1_clk, "mmc1", nand_mmc_parents, 0xd10,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+
+static const struct clk_parent_data mmc2_mmc3_parents[] = {
+	{ .hw = &sys_24M_clk.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .hw = &pll_periph1_800M_clk.common.hw },
+	{ .hw = &pll_periph1_600M_clk.hw },
+};
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc2_clk, "mmc2", mmc2_mmc3_parents, 0xd20,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc3_clk, "mmc3", mmc2_mmc3_parents, 0xd30,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+
+static const struct clk_hw *ufs_axi_parents[] = {
+	&pll_periph0_300M_clk.hw,
+	&pll_periph0_200M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ufs_axi_clk, "ufs-axi", ufs_axi_parents, 0xd80,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data ufs_cfg_parents[] = {
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ufs_cfg_clk, "ufs-cfg", ufs_cfg_parents, 0xd84,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data spi_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .hw = &pll_periph1_300M_clk.hw },
+	{ .hw = &pll_periph1_200M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi0_clk, "spi0", spi_parents, 0xf00,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi1_clk, "spi1", spi_parents, 0xf08,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi2_clk, "spi2", spi_parents, 0xf10,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data spif_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_400M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .hw = &pll_periph1_400M_clk.hw },
+	{ .hw = &pll_periph1_300M_clk.hw },
+	{ .hw = &pll_periph0_160M_clk.hw },
+	{ .hw = &pll_periph1_160M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(spif_clk, "spif", spif_parents, 0xf18,
+				  0, 5,		/* M */
+				  8, 5,		/* P */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi3_clk, "spi3", spi_parents, 0xf20,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi4_clk, "spi4", spi_parents, 0xf28,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data gpadc0_24m_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gpadc0_24m_clk, "gpadc0-24m", gpadc0_24m_parents, 0xfc0,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data irrx_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irrx_clk, "irrx", irrx_parents, 0x1000,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data irtx_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &pll_periph1_600M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irtx_clk, "irtx", irtx_parents, 0x1008,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data sgpio_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(sgpio_clk, "sgpio", sgpio_parents, 0x1060,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_hw *lpc_parents[] = {
+	&pll_video0_3x_clk.common.hw,
+	&pll_video1_3x_clk.common.hw,
+	&pll_video2_3x_clk.common.hw,
+	&pll_periph0_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(lpc_clk, "lpc", lpc_parents, 0x1080,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_200M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm0_clk, "i2spcm0", i2spcm_parents, 0x1200,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm1_clk, "i2spcm1", i2spcm_parents, 0x1210,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_clk, "i2spcm2", i2spcm_parents, 0x1220,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm2_asrc_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_periph1_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_asrc_clk, "i2spcm2_asrc", i2spcm2_asrc_parents, 0x1224,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm3_clk, "i2spcm3", i2spcm_parents, 0x1230,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm4_clk, "i2spcm4", i2spcm_parents, 0x1240,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *spdif_tx_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", spdif_tx_parents, 0x1280,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *spdif_rx_parents[] = {
+	&pll_periph0_200M_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents, 0x1284,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *dmic_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_parents, 0x12c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+/*
+ * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is
+ * a 2x multiplier from pll-ref synchronized by pll-periph0, and is also used by
+ * the OHCI module.
+ */
+static const struct clk_parent_data usb_ohci_parents[] = {
+	{ .hw = &pll_periph0_4x_clk.common.hw },
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+};
+static const struct ccu_mux_fixed_prediv usb_ohci_predivs[] = {
+	{ .index = 0, .div = 200 },
+	{ .index = 1, .div = 2 },
+};
+
+static struct ccu_mux usb_ohci0_clk = {
+	.enable		= BIT(31),
+	.mux		= {
+		.shift		= 24,
+		.width		= 2,
+		.fixed_predivs	= usb_ohci_predivs,
+		.n_predivs	= ARRAY_SIZE(usb_ohci_predivs),
+	},
+	.common		= {
+		.reg		= 0x1300,
+		.features	= CCU_FEATURE_FIXED_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("usb-ohci0", usb_ohci_parents,
+							   &ccu_mux_ops, 0),
+	},
+};
+
+static struct ccu_mux usb_ohci1_clk = {
+	.enable		= BIT(31),
+	.mux		= {
+		.shift		= 24,
+		.width		= 2,
+		.fixed_predivs	= usb_ohci_predivs,
+		.n_predivs	= ARRAY_SIZE(usb_ohci_predivs),
+	},
+	.common		= {
+		.reg		= 0x1308,
+		.features	= CCU_FEATURE_FIXED_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("usb-ohci1", usb_ohci_parents,
+							   &ccu_mux_ops, 0),
+	},
+};
+
+static const struct clk_parent_data usb01_ref_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA(usb01_ref_clk, "usb01-ref", usb01_ref_parents, 0x1340, 24, 3, 0);
+
+static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);
+
+static const struct clk_parent_data usb2_suspend_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_suspend_clk, "usb2-suspend", usb2_suspend_parents,
+				      0x1350,
+				      0, 5,	/* M */
+				      24, 1,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_mf_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_mf_clk, "usb2-mf", usb2_mf_parents,
+				      0x1354,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_u3_utmi_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_u3_utmi_clk, "usb2-u3-utmi", usb2_u3_utmi_parents,
+				      0x1360,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_u2_pipe_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_u2_pipe_clk, "usb2-u2-pipe", usb2_u2_pipe_parents,
+				      0x1364,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data pcie_aux_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(pcie_aux_clk, "pcie-aux", pcie_aux_parents, 0x1380,
+				      0, 5,	/* M */
+				      24, 1,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_hw *pcie_axi_slv_parents[] = {
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(pcie_axi_slv_clk, "pcie-axi-slv", pcie_axi_slv_parents, 0x1384,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *serdes_phy_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(serdes_phy_clk, "serdes-phy", serdes_phy_parents, 0x13c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data gmac_ptp_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gmac_ptp_clk, "gmac-ptp", gmac_ptp_parents, 0x1400,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_M_HWS_WITH_GATE(gmac0_phy_clk, "gmac0-phy", pll_periph0_150M_hws, 0x1410,
+				 0, 5,		/* M */
+				 BIT(31),	/* gate */
+				 0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_M_HWS_WITH_GATE(gmac1_phy_clk, "gmac1-phy", pll_periph0_150M_hws, 0x1420,
+				 0, 5,		/* M */
+				 BIT(31),	/* gate */
+				 0);
+
+static const struct clk_hw *tcon_lcd_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_lcd_parents, 0x1500,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_lcd_parents, 0x1508,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd2_clk, "tcon-lcd2", tcon_lcd_parents, 0x1510,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *dsi_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_200M_clk.hw,
+	&pll_periph0_150M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi0_clk, "dsi0", dsi_parents, 0x1580,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi1_clk, "dsi1", dsi_parents, 0x1588,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *combphy_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+	&pll_video0_3x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(combphy0_clk, "combphy0", combphy_parents, 0x15c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(combphy1_clk, "combphy1", combphy_parents, 0x15c4,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *edp_tv_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(edp_tv_clk, "edp-tv", edp_tv_parents, 0x1640,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k", pll_periph0_2x_hws, 0x1680,
+				      BIT(30),	/* gate */
+				      36621,	/* pre div */
+				      0);
+
+static const struct clk_parent_data hdmi_cec_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &hdmi_cec_32k_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0x1680,
+				    24, 1,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data hdmi_tv_parents[] = {
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_periph0_2x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(hdmi_tv_clk, "hdmi-tv", hdmi_tv_parents, 0x1684,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data hdmi_sfr_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_sfr_clk, "hdmi-sfr", hdmi_sfr_parents, 0x1690,
+				    24, 1,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_HWS(hdcp_esm_clk, "hdcp-esm", pll_periph0_300M_hws, 0x1694, BIT(31), 0);
+
+static const struct clk_parent_data ledc_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ledc_parents, 0x1700,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data csi_master_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video0_3x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video1_3x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_video2_3x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master0_clk, "csi_master0", csi_master_parents, 0x1800,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master1_clk, "csi_master1", csi_master_parents, 0x1804,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master2_clk, "csi_master2", csi_master_parents, 0x1808,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_hw *csi_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_clk, "csi", csi_parents, 0x1840,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *isp_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(isp_clk, "isp", isp_parents, 0x1860,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_DATA(res_dcap_24m_clk, "res-dcap-24m", hosc, 0x1a00, BIT(3), 0);
+
+static const struct clk_parent_data apb2jtag_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .hw = &pll_periph1_200M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(apb2jtag_clk, "apb2jtag", apb2jtag_parents, 0x1c00,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_GATE_HWS(fanout_24M_clk, "fanout-24M", sys_24M_hws, 0x1f30, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_12M_clk, "fanout-12M", sys_24M_hws, 0x1f30,
+				      BIT(1), 2, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_480M_hws, 0x1f30,
+				      BIT(2), 30, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_2x_hws, 0x1f30,
+				      BIT(3), 48, 0);
+
+static const struct clk_parent_data fanout_27M_parents[] = {
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(fanout_27M_clk, "fanout-27M", fanout_27M_parents, 0x1f34,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 2,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data fanout_pclk_parents[] = {
+	{ .hw = &apb0_clk.common.hw }
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(fanout_pclk_clk, "fanout-pclk", fanout_pclk_parents, 0x1f38,
+				  0, 5,		/* M */
+				  5, 5,		/* N */
+				  0, 0,		/* no mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data fanout_parents[] = {
+	{ .fw_name = "losc-fanout" },
+	{ .hw = &fanout_12M_clk.common.hw, },
+	{ .hw = &fanout_16M_clk.common.hw, },
+	{ .hw = &fanout_24M_clk.common.hw, },
+	{ .hw = &fanout_25M_clk.common.hw, },
+	{ .hw = &fanout_27M_clk.common.hw, },
+	{ .hw = &fanout_pclk_clk.common.hw, },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0x1f3c,
+				    0, 3,	/* mux */
+				    BIT(21),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0x1f3c,
+				    3, 3,	/* mux */
+				    BIT(22),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0x1f3c,
+				    6, 3,	/* mux */
+				    BIT(23),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout3_clk, "fanout3", fanout_parents, 0x1f3c,
+				    9, 3,	/* mux */
+				    BIT(24),	/* gate */
+				    0);
+
 /*
  * Contains all clocks that are controlled by a hardware register. They
  * have a (sunxi) .common member, which needs to be initialised by the common
@@ -552,6 +1465,101 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
 	&trace_clk.common,
 	&gic_clk.common,
 	&mbus_clk.common,
+	&timer0_clk.common,
+	&timer1_clk.common,
+	&timer2_clk.common,
+	&timer3_clk.common,
+	&timer4_clk.common,
+	&timer5_clk.common,
+	&timer6_clk.common,
+	&timer7_clk.common,
+	&timer8_clk.common,
+	&timer9_clk.common,
+	&avs_clk.common,
+	&de0_clk.common,
+	&di_clk.common,
+	&g2d_clk.common,
+	&eink_clk.common,
+	&eink_panel_clk.common,
+	&ve_enc0_clk.common,
+	&ve_dec0_clk.common,
+	&ce_clk.common,
+	&npu_clk.common,
+	&gpu0_clk.common,
+	&dram0_clk.common,
+	&nand0_clk0_clk.common,
+	&nand0_clk1_clk.common,
+	&mmc0_clk.common,
+	&mmc1_clk.common,
+	&mmc2_clk.common,
+	&mmc3_clk.common,
+	&ufs_axi_clk.common,
+	&ufs_cfg_clk.common,
+	&spi0_clk.common,
+	&spi1_clk.common,
+	&spi2_clk.common,
+	&spif_clk.common,
+	&spi3_clk.common,
+	&spi4_clk.common,
+	&gpadc0_24m_clk.common,
+	&irrx_clk.common,
+	&irtx_clk.common,
+	&sgpio_clk.common,
+	&lpc_clk.common,
+	&i2spcm0_clk.common,
+	&i2spcm1_clk.common,
+	&i2spcm2_clk.common,
+	&i2spcm2_asrc_clk.common,
+	&i2spcm3_clk.common,
+	&i2spcm4_clk.common,
+	&spdif_tx_clk.common,
+	&spdif_rx_clk.common,
+	&dmic_clk.common,
+	&usb_ohci0_clk.common,
+	&usb_ohci1_clk.common,
+	&usb01_ref_clk.common,
+	&usb2_u2_ref_clk.common,
+	&usb2_suspend_clk.common,
+	&usb2_mf_clk.common,
+	&usb2_u3_utmi_clk.common,
+	&usb2_u2_pipe_clk.common,
+	&pcie_aux_clk.common,
+	&pcie_axi_slv_clk.common,
+	&serdes_phy_clk.common,
+	&gmac_ptp_clk.common,
+	&gmac0_phy_clk.common,
+	&gmac1_phy_clk.common,
+	&tcon_lcd0_clk.common,
+	&tcon_lcd1_clk.common,
+	&tcon_lcd2_clk.common,
+	&dsi0_clk.common,
+	&dsi1_clk.common,
+	&combphy0_clk.common,
+	&combphy1_clk.common,
+	&edp_tv_clk.common,
+	&hdmi_cec_32k_clk.common,
+	&hdmi_cec_clk.common,
+	&hdmi_tv_clk.common,
+	&hdmi_sfr_clk.common,
+	&hdcp_esm_clk.common,
+	&ledc_clk.common,
+	&csi_master0_clk.common,
+	&csi_master1_clk.common,
+	&csi_master2_clk.common,
+	&csi_clk.common,
+	&isp_clk.common,
+	&res_dcap_24m_clk.common,
+	&apb2jtag_clk.common,
+	&fanout_24M_clk.common,
+	&fanout_12M_clk.common,
+	&fanout_16M_clk.common,
+	&fanout_25M_clk.common,
+	&fanout_27M_clk.common,
+	&fanout_pclk_clk.common,
+	&fanout0_clk.common,
+	&fanout1_clk.common,
+	&fanout2_clk.common,
+	&fanout3_clk.common,
 };
 
 static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
@@ -606,6 +1614,101 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 		[CLK_TRACE]		= &trace_clk.common.hw,
 		[CLK_GIC]		= &gic_clk.common.hw,
 		[CLK_MBUS]		= &mbus_clk.common.hw,
+		[CLK_TIMER0]		= &timer0_clk.common.hw,
+		[CLK_TIMER1]		= &timer1_clk.common.hw,
+		[CLK_TIMER2]		= &timer2_clk.common.hw,
+		[CLK_TIMER3]		= &timer3_clk.common.hw,
+		[CLK_TIMER4]		= &timer4_clk.common.hw,
+		[CLK_TIMER5]		= &timer5_clk.common.hw,
+		[CLK_TIMER6]		= &timer6_clk.common.hw,
+		[CLK_TIMER7]		= &timer7_clk.common.hw,
+		[CLK_TIMER8]		= &timer8_clk.common.hw,
+		[CLK_TIMER9]		= &timer9_clk.common.hw,
+		[CLK_AVS]		= &avs_clk.common.hw,
+		[CLK_DE0]		= &de0_clk.common.hw,
+		[CLK_DI]		= &di_clk.common.hw,
+		[CLK_G2D]		= &g2d_clk.common.hw,
+		[CLK_EINK]		= &eink_clk.common.hw,
+		[CLK_EINK_PANEL]	= &eink_panel_clk.common.hw,
+		[CLK_VE_ENC0]		= &ve_enc0_clk.common.hw,
+		[CLK_VE_DEC0]		= &ve_dec0_clk.common.hw,
+		[CLK_CE]		= &ce_clk.common.hw,
+		[CLK_NPU]		= &npu_clk.common.hw,
+		[CLK_GPU0]		= &gpu0_clk.common.hw,
+		[CLK_DRAM0]		= &dram0_clk.common.hw,
+		[CLK_NAND0_CLK0]	= &nand0_clk0_clk.common.hw,
+		[CLK_NAND0_CLK1]	= &nand0_clk1_clk.common.hw,
+		[CLK_MMC0]		= &mmc0_clk.common.hw,
+		[CLK_MMC1]		= &mmc1_clk.common.hw,
+		[CLK_MMC2]		= &mmc2_clk.common.hw,
+		[CLK_MMC3]		= &mmc3_clk.common.hw,
+		[CLK_UFS_AXI]		= &ufs_axi_clk.common.hw,
+		[CLK_UFS_CFG]		= &ufs_cfg_clk.common.hw,
+		[CLK_SPI0]		= &spi0_clk.common.hw,
+		[CLK_SPI1]		= &spi1_clk.common.hw,
+		[CLK_SPI2]		= &spi2_clk.common.hw,
+		[CLK_SPIF]		= &spif_clk.common.hw,
+		[CLK_SPI3]		= &spi3_clk.common.hw,
+		[CLK_SPI4]		= &spi4_clk.common.hw,
+		[CLK_GPADC0_24M]	= &gpadc0_24m_clk.common.hw,
+		[CLK_IRRX]		= &irrx_clk.common.hw,
+		[CLK_IRTX]		= &irtx_clk.common.hw,
+		[CLK_SGPIO]		= &sgpio_clk.common.hw,
+		[CLK_LPC]		= &lpc_clk.common.hw,
+		[CLK_I2SPCM0]		= &i2spcm0_clk.common.hw,
+		[CLK_I2SPCM1]		= &i2spcm1_clk.common.hw,
+		[CLK_I2SPCM2]		= &i2spcm2_clk.common.hw,
+		[CLK_I2SPCM2_ASRC]	= &i2spcm2_asrc_clk.common.hw,
+		[CLK_I2SPCM3]		= &i2spcm3_clk.common.hw,
+		[CLK_I2SPCM4]		= &i2spcm4_clk.common.hw,
+		[CLK_SPDIF_TX]		= &spdif_tx_clk.common.hw,
+		[CLK_SPDIF_RX]		= &spdif_rx_clk.common.hw,
+		[CLK_DMIC]		= &dmic_clk.common.hw,
+		[CLK_USB_OHCI0]		= &usb_ohci0_clk.common.hw,
+		[CLK_USB_OHCI1]		= &usb_ohci1_clk.common.hw,
+		[CLK_USB01_REF]		= &usb01_ref_clk.common.hw,
+		[CLK_USB2_U2_REF]	= &usb2_u2_ref_clk.common.hw,
+		[CLK_USB2_SUSPEND]	= &usb2_suspend_clk.common.hw,
+		[CLK_USB2_MF]		= &usb2_mf_clk.common.hw,
+		[CLK_USB2_U3_UTMI]	= &usb2_u3_utmi_clk.common.hw,
+		[CLK_USB2_U2_PIPE]	= &usb2_u2_pipe_clk.common.hw,
+		[CLK_PCIE_AUX]		= &pcie_aux_clk.common.hw,
+		[CLK_PCIE_AXI_SLV]	= &pcie_axi_slv_clk.common.hw,
+		[CLK_SERDES_PHY]	= &serdes_phy_clk.common.hw,
+		[CLK_GMAC_PTP]		= &gmac_ptp_clk.common.hw,
+		[CLK_GMAC0_PHY]		= &gmac0_phy_clk.common.hw,
+		[CLK_GMAC1_PHY]		= &gmac1_phy_clk.common.hw,
+		[CLK_TCON_LCD0]		= &tcon_lcd0_clk.common.hw,
+		[CLK_TCON_LCD1]		= &tcon_lcd1_clk.common.hw,
+		[CLK_TCON_LCD2]		= &tcon_lcd2_clk.common.hw,
+		[CLK_DSI0]		= &dsi0_clk.common.hw,
+		[CLK_DSI1]		= &dsi1_clk.common.hw,
+		[CLK_COMBPHY0]		= &combphy0_clk.common.hw,
+		[CLK_COMBPHY1]		= &combphy1_clk.common.hw,
+		[CLK_EDP_TV]		= &edp_tv_clk.common.hw,
+		[CLK_HDMI_CEC_32K]	= &hdmi_cec_32k_clk.common.hw,
+		[CLK_HDMI_CEC]		= &hdmi_cec_clk.common.hw,
+		[CLK_HDMI_TV]		= &hdmi_tv_clk.common.hw,
+		[CLK_HDMI_SFR]		= &hdmi_sfr_clk.common.hw,
+		[CLK_HDCP_ESM]		= &hdcp_esm_clk.common.hw,
+		[CLK_LEDC]		= &ledc_clk.common.hw,
+		[CLK_CSI_MASTER0]	= &csi_master0_clk.common.hw,
+		[CLK_CSI_MASTER1]	= &csi_master1_clk.common.hw,
+		[CLK_CSI_MASTER2]	= &csi_master2_clk.common.hw,
+		[CLK_CSI]		= &csi_clk.common.hw,
+		[CLK_ISP]		= &isp_clk.common.hw,
+		[CLK_RES_DCAP_24M]	= &res_dcap_24m_clk.common.hw,
+		[CLK_APB2JTAG]		= &apb2jtag_clk.common.hw,
+		[CLK_FANOUT_24M]	= &fanout_24M_clk.common.hw,
+		[CLK_FANOUT_12M]	= &fanout_12M_clk.common.hw,
+		[CLK_FANOUT_16M]	= &fanout_16M_clk.common.hw,
+		[CLK_FANOUT_25M]	= &fanout_25M_clk.common.hw,
+		[CLK_FANOUT_27M]	= &fanout_27M_clk.common.hw,
+		[CLK_FANOUT_PCLK]	= &fanout_pclk_clk.common.hw,
+		[CLK_FANOUT0]		= &fanout0_clk.common.hw,
+		[CLK_FANOUT1]		= &fanout1_clk.common.hw,
+		[CLK_FANOUT2]		= &fanout2_clk.common.hw,
+		[CLK_FANOUT3]		= &fanout3_clk.common.hw,
 	},
 	.num	= CLK_FANOUT3 + 1,
 };
Signature · 1 line
2.55.0
#12 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

Hi Junhui,

In patch 6/8, usb2-u2-ref is declared as a plain mux, but the manual has a gate at bit 31 of 0x1348, and its reset value is 0. So the CCU driver can't enable it.

-static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0); +static SUNXI_CCU_MUX_DATA_WITH_GATE(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents,
+ 0x1348, 24, 3, BIT(31), 0);

I hit this on my Cubie A7Z with a USB stick on the DWC3 port (the DT and the USB2 PHY driver for that port are local, not posted):

- v6 as posted: 0x02003348 stays 0 and the DWC3 soft reset times out (-110), 4/4 boots, one of them cold.
- same kernel, only bit 31 set from U-Boot: the host works, 3/3.
- with the change above: works, 3/3.

Same DTB and initramfs in every run. The SerDes gates were also the same, so I haven't checked whether they matter on their own.

My boot chain (U-Boot SPL, TF-A, U-Boot) leaves bit 31 clear. I don't know what the vendor one does.

Thanks,
Vinicius

#13 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

Hi Vinicius,

Quoted 3 lines · Vinicius Pedrosa

Hi Junhui,

In patch 6/8, usb2-u2-ref is declared as a plain mux, but the manual

can you please reply inline? Copy the original email, then reply after the code that you have a comment on? See the other replies on this series for examples.
After all this is the reason we do this patch-inline-in-email approach for review, so that the context is clear, and makes it easier for the author, other reviewers and maintainers to follow the review comments.

Subscribing to the linux-sunxi list is probably the easiest to get the emails, or use lore to fetch the respective emails. For one-offs you can also download the mbox file from lore, then import them in your email application.

Cheers,
Andre

P.S. This applies in general to your email replies, I see them as completely from scratch text, just with the right In-reply-to header, but without any context.

Quoted 23 lines

has a gate at bit 31 of 0x1348, and its reset value is 0. So the CCU driver can't enable it.

(quoted diff) +2 -1
-static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents,
+                                    0x1348, 24, 3, BIT(31), 0);

I hit this on my Cubie A7Z with a USB stick on the DWC3 port (the DT and the USB2 PHY driver for that port are local, not posted):

- v6 as posted: 0x02003348 stays 0 and the DWC3 soft reset times out (-110), 4/4 boots, one of them cold.
- same kernel, only bit 31 set from U-Boot: the host works, 3/3.
- with the change above: works, 3/3.

Same DTB and initramfs in every run. The SerDes gates were also the same, so I haven't checked whether they matter on their own.

My boot chain (U-Boot SPL, TF-A, U-Boot) leaves bit 31 clear. I don't know what the vendor one does.

Thanks,
Vinicius

author
#14 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

In reply to Vinicius Pedrosa

Hi Vinicius,

Thanks for reviewing and testing this.

Review

Quoted 9 lines · Vinicius Pedrosa

Hi Junhui,

In patch 6/8, usb2-u2-ref is declared as a plain mux, but the manual has a gate at bit 31 of 0x1348, and its reset value is 0. So the CCU driver can't enable it.

(quoted diff) +2 -1
-static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents,
+                                    0x1348, 24, 3, BIT(31), 0);

I'll add the missing gates to both usb01_ref_clk and usb2_u2_ref_clk in the next version.

Quoted 17 lines

I hit this on my Cubie A7Z with a USB stick on the DWC3 port (the DT and the USB2 PHY driver for that port are local, not posted):

- v6 as posted: 0x02003348 stays 0 and the DWC3 soft reset times out (-110), 4/4 boots, one of them cold.
- same kernel, only bit 31 set from U-Boot: the host works, 3/3.
- with the change above: works, 3/3.

Same DTB and initramfs in every run. The SerDes gates were also the same, so I haven't checked whether they matter on their own.

My boot chain (U-Boot SPL, TF-A, U-Boot) leaves bit 31 clear. I don't know what the vendor one does.

Thanks,
Vinicius

Signature · 2 lines
Best regards,
Junhui Liu
#15 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

In reply to Junhui Liu

Hi,

judging from the "fun" this is to review, I very much appreciate your efforts in putting this together ;-)

Quoted 104 lines · Junhui Liu

Add the module clocks found in the Allwinner A733 SoC, including video, storage, interfaces and others. While most of these clocks are similar to those in the A523 SoC, this implementation accounts for changes in register offsets and introduces support for new modules.

---
  drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 1103 ++++++++++++++++++++++++++++++++
  1 file changed, 1103 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +64 -0
index 371c4297c3ab..7847eec84313 100644
@@ -27,6 +27,7 @@
  #include "ccu_gate.h"
  #include "ccu_mp.h"
  #include "ccu_mult.h"
+#include "ccu_mux.h"
  #include "ccu_nkmp.h"
  #include "ccu_nm.h"
 
@@ -85,6 +86,9 @@ static const struct clk_hw *pll_ref_hws[] = {
   * - sys-24M serves as reference clock for downstream functional modules
   */
  static CLK_FIXED_FACTOR_HWS(sys_24M_clk, "sys-24M", pll_ref_hws, 1, 1, 0);
+static const struct clk_hw *sys_24M_hws[] = {
+	&sys_24M_clk.hw
+};
 
  #define SUN60I_A733_PLL_DDR_REG		0x020
  static struct ccu_nkmp pll_ddr_clk = {
@@ -161,6 +165,9 @@ static CLK_FIXED_FACTOR_HWS(pll_periph0_200M_clk, "pll-periph0-200M",
  			    pll_periph0_400M_hws, 2, 1, 0);
  static CLK_FIXED_FACTOR_HWS(pll_periph0_150M_clk, "pll-periph0-150M",
  			    pll_periph0_300M_hws, 2, 1, 0);
+static const struct clk_hw *pll_periph0_150M_hws[] = {
+	&pll_periph0_150M_clk.hw
+};
  static CLK_FIXED_FACTOR_HWS(pll_periph0_160M_clk, "pll-periph0-160M",
  			    pll_periph0_480M_hws, 3, 1, 0);
 
@@ -511,6 +518,912 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588
  					   CLK_IS_CRITICAL,
  					   CCU_FEATURE_UPDATE_BIT);
 
+/**************************************************************************
+ *                          mod clocks                                    *
+ **************************************************************************/
+
+static const struct clk_parent_data timer_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "iosc" },
+	{ .fw_name = "losc" },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer0_clk, "timer0", timer_parents, 0x800,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer1_clk, "timer1", timer_parents, 0x804,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer2_clk, "timer2", timer_parents, 0x808,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer3_clk, "timer3", timer_parents, 0x80c,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer4_clk, "timer4", timer_parents, 0x810,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer5_clk, "timer5", timer_parents, 0x814,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer6_clk, "timer6", timer_parents, 0x818,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer7_clk, "timer7", timer_parents, 0x81c,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer8_clk, "timer8", timer_parents, 0x820,
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer9_clk, "timer9", timer_parents, 0x824,

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 587

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+				      0, 3,		/* P */
+				      24, 3,		/* mux */
+				      BIT(31),		/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data avs_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};

Those two parents appear two more times below (usb01_ref_parents and hdmi_sfr_parents). Please rename this array to something more generic and reuse it below.

Quoted 26 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +26 -0
+static SUNXI_CCU_MUX_DATA_WITH_GATE(avs_clk, "avs-clk", avs_parents, 0x880,
+				    24, 3,		/* mux */
+				    BIT(31),		/* gate */
+				    0);
+
+static const struct clk_hw *de_parents[] = {
+	&pll_de_3x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(de0_clk, "de0", de_parents, 0xa00,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *di_parents[] = {
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 623

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", di_parents, 0xa20,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *g2d_parents[] = {
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,

My copy of the manual puts the 300MHz clock first, then the 400 MHz one. Can you please check this?

Quoted 40 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +40 -0
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", g2d_parents, 0xa40,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *eink_parents[] = {
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(eink_clk, "eink", eink_parents, 0xa60,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *eink_panel_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video0_3x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video1_3x_clk.common.hw,
+	&pll_periph0_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(eink_panel_clk, "eink-panel", eink_panel_parents, 0xa64,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ve_enc_parents[] = {
+	&pll_ve0_clk.common.hw,
+	&pll_ve1_clk.common.hw,
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+	&pll_npu_clk.common.hw,

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 673

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_enc0_clk, "ve-enc0", ve_enc_parents, 0xa80,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ve_dec_parents[] = {
+	&pll_ve1_clk.common.hw,
+	&pll_ve0_clk.common.hw,

Did AW really swap just the first two clocks between the encoder and the decoder parents? Those hardware guys ...

Quoted 55 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +55 -0
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+	&pll_npu_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_dec0_clk, "ve-dec0", ve_dec_parents, 0xa88,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *ce_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0xac0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *npu_parents[] = {
+	&pll_npu_clk.common.hw,
+	&pll_periph0_800M_clk.common.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_ve0_clk.common.hw,
+	&pll_ve1_clk.common.hw,
+	&pll_de_3x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(npu_clk, "npu", npu_parents, 0xb00,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+/*
+ * GPU_CLK = ClockSource * ((16 - M) / 16)
+ * Here we use a div_table to select M values that result in integer divisors.
+ */
+static struct clk_div_table gpu_div_table[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 8, .div = 2 },
+	{ .val = 12, .div = 4 },
+	{ .val = 14, .div = 8 },
+	{ .val = 15, .div = 16 },
+	{ /* sentinel */ },
+};
+static const struct clk_parent_data gpu_parents[] = {
+	{ .hw = &pll_gpu0_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_periph0_400M_clk.hw, },

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 738

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+	{ .hw = &pll_periph0_300M_clk.hw, },
+	{ .hw = &pll_periph0_200M_clk.hw, },
+};
+static struct ccu_div gpu0_clk = {
+	.enable		= BIT(31),
+	.div		= _SUNXI_CCU_DIV_TABLE(0, 4, gpu_div_table),
+	.mux		= _SUNXI_CCU_MUX(24, 3),
+	.common		= {
+		.reg		= 0xb20,
+		.features	= CCU_FEATURE_UPDATE_BIT,

Just a heads up: in my A523 CPU clocks series, I reworked the update bit handling, so depending on the order of merging this might need some rework.

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 748

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("gpu0", gpu_parents,
+							   &ccu_div_ops, 0),
+	}
+};
+
+static const struct clk_parent_data dram_parents[] = {
+	{ .hw = &pll_ddr_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_de_clk.common.hw, },

Should this be pll_de_3x instead?

Quoted 156 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +156 -0
+	{ .hw = &pll_npu_clk.common.hw, },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(dram0_clk, "dram0", dram_parents, 0xc00,
+					   0, 4,	/* M */
+					   24, 3,	/* mux */
+					   BIT(31),	/* gate */
+					   CLK_IS_CRITICAL,
+					   CCU_FEATURE_UPDATE_BIT);
+
+static const struct clk_parent_data nand_mmc_parents[] = {
+	{ .hw = &sys_24M_clk.hw, },
+	{ .hw = &pll_periph0_400M_clk.hw, },
+	{ .hw = &pll_periph0_300M_clk.hw, },
+	{ .hw = &pll_periph1_400M_clk.hw, },
+	{ .hw = &pll_periph1_300M_clk.hw, },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(nand0_clk0_clk, "nand0-clk0", nand_mmc_parents, 0xc80,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(nand0_clk1_clk, "nand0-clk1", nand_mmc_parents, 0xc84,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc0_clk, "mmc0", nand_mmc_parents, 0xd00,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc1_clk, "mmc1", nand_mmc_parents, 0xd10,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+
+static const struct clk_parent_data mmc2_mmc3_parents[] = {
+	{ .hw = &sys_24M_clk.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .hw = &pll_periph1_800M_clk.common.hw },
+	{ .hw = &pll_periph1_600M_clk.hw },
+};
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc2_clk, "mmc2", mmc2_mmc3_parents, 0xd20,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc3_clk, "mmc3", mmc2_mmc3_parents, 0xd30,
+					     0, 5,	/* M */
+					     8, 5,	/* P */
+					     24, 3,	/* mux */
+					     BIT(31),	/* gate */
+					     2,		/* post div */
+					     0);
+
+static const struct clk_hw *ufs_axi_parents[] = {
+	&pll_periph0_300M_clk.hw,
+	&pll_periph0_200M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ufs_axi_clk, "ufs-axi", ufs_axi_parents, 0xd80,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data ufs_cfg_parents[] = {
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ufs_cfg_clk, "ufs-cfg", ufs_cfg_parents, 0xd84,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data spi_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .hw = &pll_periph1_300M_clk.hw },
+	{ .hw = &pll_periph1_200M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi0_clk, "spi0", spi_parents, 0xf00,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi1_clk, "spi1", spi_parents, 0xf08,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi2_clk, "spi2", spi_parents, 0xf10,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data spif_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_400M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .hw = &pll_periph1_400M_clk.hw },
+	{ .hw = &pll_periph1_300M_clk.hw },
+	{ .hw = &pll_periph0_160M_clk.hw },
+	{ .hw = &pll_periph1_160M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(spif_clk, "spif", spif_parents, 0xf18,
+				  0, 5,		/* M */
+				  8, 5,		/* P */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi3_clk, "spi3", spi_parents, 0xf20,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_DUALDIV_MUX_GATE(spi4_clk, "spi4", spi_parents, 0xf28,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data gpadc0_24m_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gpadc0_24m_clk, "gpadc0-24m", gpadc0_24m_parents, 0xfc0,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data irrx_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &sys_24M_clk.hw },

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 914

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irrx_clk, "irrx", irrx_parents, 0x1000,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data irtx_parents[] = {
+	{ .fw_name = "losc"},

I think this clock should be sys_24M_clk.

Quoted 82 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +82 -0
+	{ .hw = &pll_periph1_600M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irtx_clk, "irtx", irtx_parents, 0x1008,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data sgpio_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(sgpio_clk, "sgpio", sgpio_parents, 0x1060,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_hw *lpc_parents[] = {
+	&pll_video0_3x_clk.common.hw,
+	&pll_video1_3x_clk.common.hw,
+	&pll_video2_3x_clk.common.hw,
+	&pll_periph0_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(lpc_clk, "lpc", lpc_parents, 0x1080,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_200M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm0_clk, "i2spcm0", i2spcm_parents, 0x1200,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm1_clk, "i2spcm1", i2spcm_parents, 0x1210,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_clk, "i2spcm2", i2spcm_parents, 0x1220,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm2_asrc_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_periph1_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_asrc_clk, "i2spcm2_asrc", i2spcm2_asrc_parents, 0x1224,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm3_clk, "i2spcm3", i2spcm_parents, 0x1230,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm4_clk, "i2spcm4", i2spcm_parents, 0x1240,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *spdif_tx_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1006

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", spdif_tx_parents, 0x1280,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *spdif_rx_parents[] = {
+	&pll_periph0_200M_clk.hw,
+	&pll_periph0_300M_clk.hw,

The manual I am looking at says those two muxes are "Reserved". So are those parents from the BSP? Can you please add a comment about it then?

Quoted 64 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +64 -0
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents, 0x1284,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *dmic_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_parents, 0x12c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+/*
+ * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is
+ * a 2x multiplier from pll-ref synchronized by pll-periph0, and is also used by
+ * the OHCI module.
+ */
+static const struct clk_parent_data usb_ohci_parents[] = {
+	{ .hw = &pll_periph0_4x_clk.common.hw },
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+};
+static const struct ccu_mux_fixed_prediv usb_ohci_predivs[] = {
+	{ .index = 0, .div = 200 },
+	{ .index = 1, .div = 2 },
+};
+
+static struct ccu_mux usb_ohci0_clk = {
+	.enable		= BIT(31),
+	.mux		= {
+		.shift		= 24,
+		.width		= 2,
+		.fixed_predivs	= usb_ohci_predivs,
+		.n_predivs	= ARRAY_SIZE(usb_ohci_predivs),
+	},
+	.common		= {
+		.reg		= 0x1300,
+		.features	= CCU_FEATURE_FIXED_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("usb-ohci0", usb_ohci_parents,
+							   &ccu_mux_ops, 0),
+	},
+};
+
+static struct ccu_mux usb_ohci1_clk = {
+	.enable		= BIT(31),
+	.mux		= {
+		.shift		= 24,
+		.width		= 2,
+		.fixed_predivs	= usb_ohci_predivs,
+		.n_predivs	= ARRAY_SIZE(usb_ohci_predivs),
+	},
+	.common		= {
+		.reg		= 0x1308,
+		.features	= CCU_FEATURE_FIXED_PREDIV,
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("usb-ohci1", usb_ohci_parents,
+							   &ccu_mux_ops, 0),

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1080

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+	},
+};
+
+static const struct clk_parent_data usb01_ref_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA(usb01_ref_clk, "usb01-ref", usb01_ref_parents, 0x1340, 24, 3, 0);
+
+static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);

Don't these two clocks miss the gate at bit 31? So it should be SUNXI_CCU_MUX_DATA_WITH_GATE instead?

Quoted 18 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +18 -0
+
+static const struct clk_parent_data usb2_suspend_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_suspend_clk, "usb2-suspend", usb2_suspend_parents,
+				      0x1350,
+				      0, 5,	/* M */
+				      24, 1,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_mf_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_mf_clk, "usb2-mf", usb2_mf_parents,

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1108

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+				      0x1354,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_u3_utmi_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },

Aren't those parents exactly the same as the usb2_mf_parents[] above?

Quoted 130 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +130 -0
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_u3_utmi_clk, "usb2-u3-utmi", usb2_u3_utmi_parents,
+				      0x1360,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_u2_pipe_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_u2_pipe_clk, "usb2-u2-pipe", usb2_u2_pipe_parents,
+				      0x1364,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data pcie_aux_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(pcie_aux_clk, "pcie-aux", pcie_aux_parents, 0x1380,
+				      0, 5,	/* M */
+				      24, 1,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_hw *pcie_axi_slv_parents[] = {
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(pcie_axi_slv_clk, "pcie-axi-slv", pcie_axi_slv_parents, 0x1384,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *serdes_phy_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(serdes_phy_clk, "serdes-phy", serdes_phy_parents, 0x13c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data gmac_ptp_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gmac_ptp_clk, "gmac-ptp", gmac_ptp_parents, 0x1400,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_M_HWS_WITH_GATE(gmac0_phy_clk, "gmac0-phy", pll_periph0_150M_hws, 0x1410,
+				 0, 5,		/* M */
+				 BIT(31),	/* gate */
+				 0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_M_HWS_WITH_GATE(gmac1_phy_clk, "gmac1-phy", pll_periph0_150M_hws, 0x1420,
+				 0, 5,		/* M */
+				 BIT(31),	/* gate */
+				 0);
+
+static const struct clk_hw *tcon_lcd_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_lcd_parents, 0x1500,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_lcd_parents, 0x1508,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd2_clk, "tcon-lcd2", tcon_lcd_parents, 0x1510,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *dsi_parents[] = {
+	&sys_24M_clk.hw,
+	&pll_periph0_200M_clk.hw,
+	&pll_periph0_150M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi0_clk, "dsi0", dsi_parents, 0x1580,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi1_clk, "dsi1", dsi_parents, 0x1588,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *combphy_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+	&pll_video0_3x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(combphy0_clk, "combphy0", combphy_parents, 0x15c0,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(combphy1_clk, "combphy1", combphy_parents, 0x15c4,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *edp_tv_parents[] = {

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1248

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(edp_tv_clk, "edp-tv", edp_tv_parents, 0x1640,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);

There is a second divider range from bits [12:8].

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1260

Quoted 12 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +12 -0
+
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k", pll_periph0_2x_hws, 0x1680,
+				      BIT(30),	/* gate */
+				      36621,	/* pre div */
+				      0);
+
+static const struct clk_parent_data hdmi_cec_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &hdmi_cec_32k_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0x1680,
+				    24, 1,	/* mux */

Even though there are indeed only two choices, the manual still specifies the mux bits as ranging from [26:24] (as for many other clocks).

Quoted 62 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +62 -0
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data hdmi_tv_parents[] = {
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_periph0_2x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(hdmi_tv_clk, "hdmi-tv", hdmi_tv_parents, 0x1684,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data hdmi_sfr_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_sfr_clk, "hdmi-sfr", hdmi_sfr_parents, 0x1690,
+				    24, 1,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_HWS(hdcp_esm_clk, "hdcp-esm", pll_periph0_300M_hws, 0x1694, BIT(31), 0);
+
+static const struct clk_parent_data ledc_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ledc_parents, 0x1700,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data csi_master_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video0_3x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video1_3x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_video2_3x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master0_clk, "csi_master0", csi_master_parents, 0x1800,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master1_clk, "csi_master1", csi_master_parents, 0x1804,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master2_clk, "csi_master2", csi_master_parents, 0x1808,
+				  0, 5,		/* M */
+				  8, 5,		/* N */

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1332

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_hw *csi_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,

My manual lists two more parents: video0_4x and video1_4x.

Quoted 35 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +35 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_clk, "csi", csi_parents, 0x1840,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *isp_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(isp_clk, "isp", isp_parents, 0x1860,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_DATA(res_dcap_24m_clk, "res-dcap-24m", hosc, 0x1a00, BIT(3), 0);
+
+static const struct clk_parent_data apb2jtag_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .hw = &pll_periph1_200M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(apb2jtag_clk, "apb2jtag", apb2jtag_parents, 0x1c00,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1377

Quoted 10 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_GATE_HWS(fanout_24M_clk, "fanout-24M", sys_24M_hws, 0x1f30, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_12M_clk, "fanout-12M", sys_24M_hws, 0x1f30,
+				      BIT(1), 2, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_480M_hws, 0x1f30,
+				      BIT(2), 30, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_2x_hws, 0x1f30,
+				      BIT(3), 48, 0);

Where do those parents come from? My manual just lists the frequencies. Is that matching the 0x1f3c register sources?

The rest seems to be correct, as far as my mostly manual comparison goes.

Cheers,
Andre

Quoted 257 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +239 -0
+
+static const struct clk_parent_data fanout_27M_parents[] = {
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(fanout_27M_clk, "fanout-27M", fanout_27M_parents, 0x1f34,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 2,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data fanout_pclk_parents[] = {
+	{ .hw = &apb0_clk.common.hw }
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(fanout_pclk_clk, "fanout-pclk", fanout_pclk_parents, 0x1f38,
+				  0, 5,		/* M */
+				  5, 5,		/* N */
+				  0, 0,		/* no mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data fanout_parents[] = {
+	{ .fw_name = "losc-fanout" },
+	{ .hw = &fanout_12M_clk.common.hw, },
+	{ .hw = &fanout_16M_clk.common.hw, },
+	{ .hw = &fanout_24M_clk.common.hw, },
+	{ .hw = &fanout_25M_clk.common.hw, },
+	{ .hw = &fanout_27M_clk.common.hw, },
+	{ .hw = &fanout_pclk_clk.common.hw, },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0x1f3c,
+				    0, 3,	/* mux */
+				    BIT(21),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0x1f3c,
+				    3, 3,	/* mux */
+				    BIT(22),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0x1f3c,
+				    6, 3,	/* mux */
+				    BIT(23),	/* gate */
+				    0);
+static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout3_clk, "fanout3", fanout_parents, 0x1f3c,
+				    9, 3,	/* mux */
+				    BIT(24),	/* gate */
+				    0);
+
  /*
   * Contains all clocks that are controlled by a hardware register. They
   * have a (sunxi) .common member, which needs to be initialised by the common
@@ -552,6 +1465,101 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
  	&trace_clk.common,
  	&gic_clk.common,
  	&mbus_clk.common,
+	&timer0_clk.common,
+	&timer1_clk.common,
+	&timer2_clk.common,
+	&timer3_clk.common,
+	&timer4_clk.common,
+	&timer5_clk.common,
+	&timer6_clk.common,
+	&timer7_clk.common,
+	&timer8_clk.common,
+	&timer9_clk.common,
+	&avs_clk.common,
+	&de0_clk.common,
+	&di_clk.common,
+	&g2d_clk.common,
+	&eink_clk.common,
+	&eink_panel_clk.common,
+	&ve_enc0_clk.common,
+	&ve_dec0_clk.common,
+	&ce_clk.common,
+	&npu_clk.common,
+	&gpu0_clk.common,
+	&dram0_clk.common,
+	&nand0_clk0_clk.common,
+	&nand0_clk1_clk.common,
+	&mmc0_clk.common,
+	&mmc1_clk.common,
+	&mmc2_clk.common,
+	&mmc3_clk.common,
+	&ufs_axi_clk.common,
+	&ufs_cfg_clk.common,
+	&spi0_clk.common,
+	&spi1_clk.common,
+	&spi2_clk.common,
+	&spif_clk.common,
+	&spi3_clk.common,
+	&spi4_clk.common,
+	&gpadc0_24m_clk.common,
+	&irrx_clk.common,
+	&irtx_clk.common,
+	&sgpio_clk.common,
+	&lpc_clk.common,
+	&i2spcm0_clk.common,
+	&i2spcm1_clk.common,
+	&i2spcm2_clk.common,
+	&i2spcm2_asrc_clk.common,
+	&i2spcm3_clk.common,
+	&i2spcm4_clk.common,
+	&spdif_tx_clk.common,
+	&spdif_rx_clk.common,
+	&dmic_clk.common,
+	&usb_ohci0_clk.common,
+	&usb_ohci1_clk.common,
+	&usb01_ref_clk.common,
+	&usb2_u2_ref_clk.common,
+	&usb2_suspend_clk.common,
+	&usb2_mf_clk.common,
+	&usb2_u3_utmi_clk.common,
+	&usb2_u2_pipe_clk.common,
+	&pcie_aux_clk.common,
+	&pcie_axi_slv_clk.common,
+	&serdes_phy_clk.common,
+	&gmac_ptp_clk.common,
+	&gmac0_phy_clk.common,
+	&gmac1_phy_clk.common,
+	&tcon_lcd0_clk.common,
+	&tcon_lcd1_clk.common,
+	&tcon_lcd2_clk.common,
+	&dsi0_clk.common,
+	&dsi1_clk.common,
+	&combphy0_clk.common,
+	&combphy1_clk.common,
+	&edp_tv_clk.common,
+	&hdmi_cec_32k_clk.common,
+	&hdmi_cec_clk.common,
+	&hdmi_tv_clk.common,
+	&hdmi_sfr_clk.common,
+	&hdcp_esm_clk.common,
+	&ledc_clk.common,
+	&csi_master0_clk.common,
+	&csi_master1_clk.common,
+	&csi_master2_clk.common,
+	&csi_clk.common,
+	&isp_clk.common,
+	&res_dcap_24m_clk.common,
+	&apb2jtag_clk.common,
+	&fanout_24M_clk.common,
+	&fanout_12M_clk.common,
+	&fanout_16M_clk.common,
+	&fanout_25M_clk.common,
+	&fanout_27M_clk.common,
+	&fanout_pclk_clk.common,
+	&fanout0_clk.common,
+	&fanout1_clk.common,
+	&fanout2_clk.common,
+	&fanout3_clk.common,
  };
 
  static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
@@ -606,6 +1614,101 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
  		[CLK_TRACE]		= &trace_clk.common.hw,
  		[CLK_GIC]		= &gic_clk.common.hw,
  		[CLK_MBUS]		= &mbus_clk.common.hw,
+		[CLK_TIMER0]		= &timer0_clk.common.hw,
+		[CLK_TIMER1]		= &timer1_clk.common.hw,
+		[CLK_TIMER2]		= &timer2_clk.common.hw,
+		[CLK_TIMER3]		= &timer3_clk.common.hw,
+		[CLK_TIMER4]		= &timer4_clk.common.hw,
+		[CLK_TIMER5]		= &timer5_clk.common.hw,
+		[CLK_TIMER6]		= &timer6_clk.common.hw,
+		[CLK_TIMER7]		= &timer7_clk.common.hw,
+		[CLK_TIMER8]		= &timer8_clk.common.hw,
+		[CLK_TIMER9]		= &timer9_clk.common.hw,
+		[CLK_AVS]		= &avs_clk.common.hw,
+		[CLK_DE0]		= &de0_clk.common.hw,
+		[CLK_DI]		= &di_clk.common.hw,
+		[CLK_G2D]		= &g2d_clk.common.hw,
+		[CLK_EINK]		= &eink_clk.common.hw,
+		[CLK_EINK_PANEL]	= &eink_panel_clk.common.hw,
+		[CLK_VE_ENC0]		= &ve_enc0_clk.common.hw,
+		[CLK_VE_DEC0]		= &ve_dec0_clk.common.hw,
+		[CLK_CE]		= &ce_clk.common.hw,
+		[CLK_NPU]		= &npu_clk.common.hw,
+		[CLK_GPU0]		= &gpu0_clk.common.hw,
+		[CLK_DRAM0]		= &dram0_clk.common.hw,
+		[CLK_NAND0_CLK0]	= &nand0_clk0_clk.common.hw,
+		[CLK_NAND0_CLK1]	= &nand0_clk1_clk.common.hw,
+		[CLK_MMC0]		= &mmc0_clk.common.hw,
+		[CLK_MMC1]		= &mmc1_clk.common.hw,
+		[CLK_MMC2]		= &mmc2_clk.common.hw,
+		[CLK_MMC3]		= &mmc3_clk.common.hw,
+		[CLK_UFS_AXI]		= &ufs_axi_clk.common.hw,
+		[CLK_UFS_CFG]		= &ufs_cfg_clk.common.hw,
+		[CLK_SPI0]		= &spi0_clk.common.hw,
+		[CLK_SPI1]		= &spi1_clk.common.hw,
+		[CLK_SPI2]		= &spi2_clk.common.hw,
+		[CLK_SPIF]		= &spif_clk.common.hw,
+		[CLK_SPI3]		= &spi3_clk.common.hw,
+		[CLK_SPI4]		= &spi4_clk.common.hw,
+		[CLK_GPADC0_24M]	= &gpadc0_24m_clk.common.hw,
+		[CLK_IRRX]		= &irrx_clk.common.hw,
+		[CLK_IRTX]		= &irtx_clk.common.hw,
+		[CLK_SGPIO]		= &sgpio_clk.common.hw,
+		[CLK_LPC]		= &lpc_clk.common.hw,
+		[CLK_I2SPCM0]		= &i2spcm0_clk.common.hw,
+		[CLK_I2SPCM1]		= &i2spcm1_clk.common.hw,
+		[CLK_I2SPCM2]		= &i2spcm2_clk.common.hw,
+		[CLK_I2SPCM2_ASRC]	= &i2spcm2_asrc_clk.common.hw,
+		[CLK_I2SPCM3]		= &i2spcm3_clk.common.hw,
+		[CLK_I2SPCM4]		= &i2spcm4_clk.common.hw,
+		[CLK_SPDIF_TX]		= &spdif_tx_clk.common.hw,
+		[CLK_SPDIF_RX]		= &spdif_rx_clk.common.hw,
+		[CLK_DMIC]		= &dmic_clk.common.hw,
+		[CLK_USB_OHCI0]		= &usb_ohci0_clk.common.hw,
+		[CLK_USB_OHCI1]		= &usb_ohci1_clk.common.hw,
+		[CLK_USB01_REF]		= &usb01_ref_clk.common.hw,
+		[CLK_USB2_U2_REF]	= &usb2_u2_ref_clk.common.hw,
+		[CLK_USB2_SUSPEND]	= &usb2_suspend_clk.common.hw,
+		[CLK_USB2_MF]		= &usb2_mf_clk.common.hw,
+		[CLK_USB2_U3_UTMI]	= &usb2_u3_utmi_clk.common.hw,
+		[CLK_USB2_U2_PIPE]	= &usb2_u2_pipe_clk.common.hw,
+		[CLK_PCIE_AUX]		= &pcie_aux_clk.common.hw,
+		[CLK_PCIE_AXI_SLV]	= &pcie_axi_slv_clk.common.hw,
+		[CLK_SERDES_PHY]	= &serdes_phy_clk.common.hw,
+		[CLK_GMAC_PTP]		= &gmac_ptp_clk.common.hw,
+		[CLK_GMAC0_PHY]		= &gmac0_phy_clk.common.hw,
+		[CLK_GMAC1_PHY]		= &gmac1_phy_clk.common.hw,
+		[CLK_TCON_LCD0]		= &tcon_lcd0_clk.common.hw,
+		[CLK_TCON_LCD1]		= &tcon_lcd1_clk.common.hw,
+		[CLK_TCON_LCD2]		= &tcon_lcd2_clk.common.hw,
+		[CLK_DSI0]		= &dsi0_clk.common.hw,
+		[CLK_DSI1]		= &dsi1_clk.common.hw,
+		[CLK_COMBPHY0]		= &combphy0_clk.common.hw,
+		[CLK_COMBPHY1]		= &combphy1_clk.common.hw,
+		[CLK_EDP_TV]		= &edp_tv_clk.common.hw,
+		[CLK_HDMI_CEC_32K]	= &hdmi_cec_32k_clk.common.hw,
+		[CLK_HDMI_CEC]		= &hdmi_cec_clk.common.hw,
+		[CLK_HDMI_TV]		= &hdmi_tv_clk.common.hw,
+		[CLK_HDMI_SFR]		= &hdmi_sfr_clk.common.hw,
+		[CLK_HDCP_ESM]		= &hdcp_esm_clk.common.hw,
+		[CLK_LEDC]		= &ledc_clk.common.hw,
+		[CLK_CSI_MASTER0]	= &csi_master0_clk.common.hw,
+		[CLK_CSI_MASTER1]	= &csi_master1_clk.common.hw,
+		[CLK_CSI_MASTER2]	= &csi_master2_clk.common.hw,
+		[CLK_CSI]		= &csi_clk.common.hw,
+		[CLK_ISP]		= &isp_clk.common.hw,
+		[CLK_RES_DCAP_24M]	= &res_dcap_24m_clk.common.hw,
+		[CLK_APB2JTAG]		= &apb2jtag_clk.common.hw,
+		[CLK_FANOUT_24M]	= &fanout_24M_clk.common.hw,
+		[CLK_FANOUT_12M]	= &fanout_12M_clk.common.hw,
+		[CLK_FANOUT_16M]	= &fanout_16M_clk.common.hw,
+		[CLK_FANOUT_25M]	= &fanout_25M_clk.common.hw,
+		[CLK_FANOUT_27M]	= &fanout_27M_clk.common.hw,
+		[CLK_FANOUT_PCLK]	= &fanout_pclk_clk.common.hw,
+		[CLK_FANOUT0]		= &fanout0_clk.common.hw,
+		[CLK_FANOUT1]		= &fanout1_clk.common.hw,
+		[CLK_FANOUT2]		= &fanout2_clk.common.hw,
+		[CLK_FANOUT3]		= &fanout3_clk.common.hw,
  	},
  	.num	= CLK_FANOUT3 + 1,
  };
#16 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

Hi Andre,

On 11/2/26 16:32, Andre Przywara wrote:
[...]

Quoted 10 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1080

Quoted 7 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +7 -0
+static const struct clk_parent_data usb01_ref_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA(usb01_ref_clk, "usb01-ref", usb01_ref_parents, 0x1340, 24, 3, 0);
+
+static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);

Don't these two clocks miss the gate at bit 31? So it should be SUNXI_CCU_MUX_DATA_WITH_GATE instead?

Yes, both have the gate at bit 31 in the manual, and the vendor CCU models 0x1340 with it too. usb2-u2-ref resets to off, which is the one I hit on my board. usb01-ref resets to on, so nothing breaks today.

With the gate added, clk_disable_unused would switch usb01-ref off unless something claims it, and in my local DT nothing does (the USB0/USB1 PHYs take osc24M like the A523 ones). On my Cubie A7Z, clearing bit 31 of 0x1340 at runtime stops the USB1 Wi-Fi traffic, and after rebinding EHCI1/OHCI1 the device no longer enumerates (error -62), 4 out of 4, while it enumerates again with the bit set. So at least USB1 will need CLK_USB01_REF kept enabled once the gate is added, likely through a consumer in the USB controller or PHY, as suggested by the vendor DT. I only tested USB1, by writing the register, not the gated CCU itself.

Thanks also for your guidance throughout these discussions.

Thanks,
Vinicius

author
#17 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

In reply to Andre Przywara

Hi Andre,

Thanks for your patient review.

Besides the issues you pointed out, I also found a few other places that don't match the manual. I'll fix those in the next version as well.

Quoted 17 lines · Andre Przywara

Hi,

judging from the "fun" this is to review, I very much appreciate your efforts in putting this together ;-)

Quoted 11 lines · Junhui Liu

Add the module clocks found in the Allwinner A733 SoC, including video, storage, interfaces and others. While most of these clocks are similar to those in the A523 SoC, this implementation accounts for changes in register offsets and introduces support for new modules.

---
  drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 1103 ++++++++++++++++++++++++++++++++
  1 file changed, 1103 insertions(+)

[...]

Quoted 10 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 587

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data avs_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};

Those two parents appear two more times below (usb01_ref_parents and hdmi_sfr_parents). Please rename this array to something more generic and reuse it below.

Okay, I'll rename it to sys_24M_hosc_parents and reuse it for those clocks.

Quoted 32 lines
Quoted 32 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +31 -0
+static SUNXI_CCU_MUX_DATA_WITH_GATE(avs_clk, "avs-clk", avs_parents, 0x880,
+				    24, 3,		/* mux */
+				    BIT(31),		/* gate */
+				    0);
+
+static const struct clk_hw *de_parents[] = {
+	&pll_de_3x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(de0_clk, "de0", de_parents, 0xa00,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *di_parents[] = {
+	&pll_periph0_600M_clk.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", di_parents, 0xa20,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 623

Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+				    CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *g2d_parents[] = {
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_300M_clk.hw,

My copy of the manual puts the 300MHz clock first, then the 400 MHz one. Can you please check this?

Yes, I checked the manual, and the first parent is indeed 300MHz.

The last parent should also be pll_video2_4x rather than pll_video1_4x. I'll fix both.

[...]

Quoted 23 lines
Quoted 23 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +23 -0
+
+/*
+ * GPU_CLK = ClockSource * ((16 - M) / 16)
+ * Here we use a div_table to select M values that result in integer divisors.
+ */
+static struct clk_div_table gpu_div_table[] = {
+	{ .val = 0, .div = 1 },
+	{ .val = 8, .div = 2 },
+	{ .val = 12, .div = 4 },
+	{ .val = 14, .div = 8 },
+	{ .val = 15, .div = 16 },
+	{ /* sentinel */ },
+};
+static const struct clk_parent_data gpu_parents[] = {
+	{ .hw = &pll_gpu0_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_periph0_400M_clk.hw, },
+	{ .hw = &pll_periph0_300M_clk.hw, },
+	{ .hw = &pll_periph0_200M_clk.hw, },
+};
+static struct ccu_div gpu0_clk = {
+	.enable		= BIT(31),
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 738

Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+	.div		= _SUNXI_CCU_DIV_TABLE(0, 4, gpu_div_table),
+	.mux		= _SUNXI_CCU_MUX(24, 3),
+	.common		= {
+		.reg		= 0xb20,
+		.features	= CCU_FEATURE_UPDATE_BIT,

Just a heads up: in my A523 CPU clocks series, I reworked the update bit handling, so depending on the order of merging this might need some rework.

I've seen that. I'd prefer to keep this series independent of your A523 CPU clocks series for now. Once your series has settled, I'll send a separate patch to adapt the A733 update bit handling, or update this series if yours lands first.

Quoted 13 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 748

Quoted 11 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +10 -0
+		.hw.init	= CLK_HW_INIT_PARENTS_DATA("gpu0", gpu_parents,
+							   &ccu_div_ops, 0),
+	}
+};
+
+static const struct clk_parent_data dram_parents[] = {
+	{ .hw = &pll_ddr_clk.common.hw, },
+	{ .hw = &pll_periph0_800M_clk.common.hw, },
+	{ .hw = &pll_periph0_600M_clk.hw, },
+	{ .hw = &pll_de_clk.common.hw, },

Should this be pll_de_3x instead?

You're right. The second and third parents should also be periph1 rather than periph0. I'll fix them together.

[...]

Quoted 5 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 914

Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +3 -0
+
+static const struct clk_parent_data irtx_parents[] = {
+	{ .fw_name = "losc"},

I think this clock should be sys_24M_clk.

You're right. I'll fix it.

Quoted 88 lines
Quoted 88 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +87 -0
+	{ .hw = &pll_periph1_600M_clk.hw },
+	{ .fw_name = "hosc"},
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irtx_clk, "irtx", irtx_parents, 0x1008,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_parent_data sgpio_parents[] = {
+	{ .fw_name = "losc"},
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(sgpio_clk, "sgpio", sgpio_parents, 0x1060,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+/* Undocumented, taken from the vendor kernel. */
+static const struct clk_hw *lpc_parents[] = {
+	&pll_video0_3x_clk.common.hw,
+	&pll_video1_3x_clk.common.hw,
+	&pll_video2_3x_clk.common.hw,
+	&pll_periph0_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(lpc_clk, "lpc", lpc_parents, 0x1080,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_200M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm0_clk, "i2spcm0", i2spcm_parents, 0x1200,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm1_clk, "i2spcm1", i2spcm_parents, 0x1210,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_clk, "i2spcm2", i2spcm_parents, 0x1220,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *i2spcm2_asrc_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+	&pll_periph0_300M_clk.hw,
+	&pll_periph1_300M_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_asrc_clk, "i2spcm2_asrc", i2spcm2_asrc_parents, 0x1224,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm3_clk, "i2spcm3", i2spcm_parents, 0x1230,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm4_clk, "i2spcm4", i2spcm_parents, 0x1240,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *spdif_tx_parents[] = {
+	&pll_audio0_4x_clk.common.hw,
+	&pll_audio1_div2_clk.hw,
+	&pll_audio1_div5_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", spdif_tx_parents, 0x1280,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1006

Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+				    0);
+
+static const struct clk_hw *spdif_rx_parents[] = {
+	&pll_periph0_200M_clk.hw,
+	&pll_periph0_300M_clk.hw,

The manual I am looking at says those two muxes are "Reserved". So are those parents from the BSP? Can you please add a comment about it then?

Yes, I took them from the vendor BSP. I'll add a comment explaining that.

[...]

Quoted 11 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1080

Quoted 8 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +8 -0
+
+static const struct clk_parent_data usb01_ref_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA(usb01_ref_clk, "usb01-ref", usb01_ref_parents, 0x1340, 24, 3, 0);
+
+static SUNXI_CCU_MUX_DATA(usb2_u2_ref_clk, "usb2-u2-ref", usb01_ref_parents, 0x1348, 24, 3, 0);

Don't these two clocks miss the gate at bit 31? So it should be SUNXI_CCU_MUX_DATA_WITH_GATE instead?

Oops, I missed them. I'll add them.

Quoted 23 lines
Quoted 23 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +22 -0
+
+static const struct clk_parent_data usb2_suspend_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &sys_24M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_suspend_clk, "usb2-suspend", usb2_suspend_parents,
+				      0x1350,
+				      0, 5,	/* M */
+				      24, 1,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data usb2_mf_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb2_mf_clk, "usb2-mf", usb2_mf_parents,
+				      0x1354,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1108

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+				      0);
+
+static const struct clk_parent_data usb2_u3_utmi_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_300M_clk.hw },
+	{ .fw_name = "hosc" },

Aren't those parents exactly the same as the usb2_mf_parents[] above?

Yes, I'll reuse the array.

[...]

Quoted 6 lines
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+
+static const struct clk_hw *edp_tv_parents[] = {
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_2x_clk.common.hw,
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1248

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(edp_tv_clk, "edp-tv", edp_tv_parents, 0x1640,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);

There is a second divider range from bits [12:8].

Okay, I'll switch this to SUNXI_CCU_DUALDIV_MUX_GATE.

Quoted 16 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1260

Quoted 13 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +12 -0
+
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k", pll_periph0_2x_hws, 0x1680,
+				      BIT(30),	/* gate */
+				      36621,	/* pre div */
+				      0);
+
+static const struct clk_parent_data hdmi_cec_parents[] = {
+	{ .fw_name = "losc" },
+	{ .hw = &hdmi_cec_32k_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0x1680,
+				    24, 1,	/* mux */

Even though there are indeed only two choices, the manual still specifies the mux bits as ranging from [26:24] (as for many other clocks).

Okay, I'll update the mux width.

Quoted 67 lines
Quoted 67 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +66 -0
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_parent_data hdmi_tv_parents[] = {
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_periph0_2x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(hdmi_tv_clk, "hdmi-tv", hdmi_tv_parents, 0x1684,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
+static const struct clk_parent_data hdmi_sfr_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_sfr_clk, "hdmi-sfr", hdmi_sfr_parents, 0x1690,
+				    24, 1,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_HWS(hdcp_esm_clk, "hdcp-esm", pll_periph0_300M_hws, 0x1694, BIT(31), 0);
+
+static const struct clk_parent_data ledc_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_periph0_600M_clk.hw },
+	{ .fw_name = "hosc" },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ledc_parents, 0x1700,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static const struct clk_parent_data csi_master_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .hw = &pll_video0_4x_clk.common.hw },
+	{ .hw = &pll_video0_3x_clk.common.hw },
+	{ .hw = &pll_video1_4x_clk.common.hw },
+	{ .hw = &pll_video1_3x_clk.common.hw },
+	{ .hw = &pll_video2_4x_clk.common.hw },
+	{ .hw = &pll_video2_3x_clk.common.hw },
+};
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master0_clk, "csi_master0", csi_master_parents, 0x1800,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master1_clk, "csi_master1", csi_master_parents, 0x1804,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+static SUNXI_CCU_DUALDIV_MUX_GATE(csi_master2_clk, "csi_master2", csi_master_parents, 0x1808,
+				  0, 5,		/* M */
+				  8, 5,		/* N */
+				  24, 3,	/* mux */
+				  BIT(31),	/* gate */
+				  0);
+
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1332

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+static const struct clk_hw *csi_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_de_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,

My manual lists two more parents: video0_4x and video1_4x.

I missed them. I'll add them.

Quoted 41 lines
Quoted 41 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +40 -0
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_clk, "csi", csi_parents, 0x1840,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static const struct clk_hw *isp_parents[] = {
+	&pll_video2_4x_clk.common.hw,
+	&pll_periph0_480M_clk.common.hw,
+	&pll_periph0_400M_clk.hw,
+	&pll_periph0_600M_clk.hw,
+	&pll_video0_4x_clk.common.hw,
+	&pll_video1_4x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(isp_clk, "isp", isp_parents, 0x1860,
+				    0, 5,	/* M */
+				    24, 3,	/* mux */
+				    BIT(31),	/* gate */
+				    0);
+
+static SUNXI_CCU_GATE_DATA(res_dcap_24m_clk, "res-dcap-24m", hosc, 0x1a00, BIT(3), 0);
+
+static const struct clk_parent_data apb2jtag_parents[] = {
+	{ .hw = &sys_24M_clk.hw },
+	{ .fw_name = "losc" },
+	{ .fw_name = "iosc" },
+	{ .hw = &pll_periph0_480M_clk.common.hw },
+	{ .hw = &pll_periph1_480M_clk.common.hw },
+	{ .hw = &pll_periph0_200M_clk.hw },
+	{ .hw = &pll_periph1_200M_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(apb2jtag_clk, "apb2jtag", apb2jtag_parents, 0x1c00,
+				      0, 5,	/* M */
+				      24, 3,	/* mux */
+				      BIT(31),	/* gate */
+				      0);
+
+static SUNXI_CCU_GATE_HWS(fanout_24M_clk, "fanout-24M", sys_24M_hws, 0x1f30, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_12M_clk, "fanout-12M", sys_24M_hws, 0x1f30,
Quoted 8 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 1377

Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+				      BIT(1), 2, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_480M_hws, 0x1f30,
+				      BIT(2), 30, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_2x_hws, 0x1f30,
+				      BIT(3), 48, 0);

Where do those parents come from? My manual just lists the frequencies. Is that matching the 0x1f3c register sources?

Yes, these match the sources listed in CCMU_FAN_REG (0x1f3c).

The current definitions fold the intermediate fixed dividers:
PERI0_160M / 10 becomes PERI0_480M / 30, and PERI0_150M / 6 becomes PERI0PLL2X / 48.

I'll use PERI0_160M / 10 and PERI0_150M / 6 in the next revision to match the documented clock tree more directly.

Quoted 6 lines

The rest seems to be correct, as far as my mostly manual comparison goes.

Cheers,
Andre

Signature · 2 lines
Best regards,
Junhui Liu
maintainer
#18 lore raw

Re: [PATCH v6 6/8] clk: sunxi-ng: a733: Add mod clocks support

In reply to Junhui Liu
Quoted 16 lines · Junhui Liu

Add the module clocks found in the Allwinner A733 SoC, including video, storage, interfaces and others. While most of these clocks are similar to those in the A523 SoC, this implementation accounts for changes in register offsets and introduces support for new modules.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 1103 ++++++++++++++++++++++++++++++++
 1 file changed, 1103 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +0 -0
index 371c4297c3ab..7847eec84313 100644

[...]

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 752

Quoted 9 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +9 -0
+static const struct clk_parent_data dram_parents[] = {
+       { .hw = &pll_ddr_clk.common.hw, },
+       { .hw = &pll_periph0_800M_clk.common.hw, },
+       { .hw = &pll_periph0_600M_clk.hw, },
+       { .hw = &pll_de_clk.common.hw, },
+       { .hw = &pll_npu_clk.common.hw, },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(dram0_clk, "dram0", dram_parents, 0xc00,
+                                          0, 4,        /* M */

My LLM agent flagged this: the divider is 5 bits wide, not 4. Both the user manual (page 149 from start or 128 as numbered on the page) and the BSP agree.

ChenYu

author
#19 lore raw

PATCH v6 7/8 clk: sunxi-ng: a733: Add bus clock gates

In reply to Junhui Liu

Add the bus clock gates that control access to the devices' register interface on the Allwinner A733 SoC. These clocks are typically single-bit controls in the BGR registers, covering UARTs, SPI, I2C, and various multimedia engines. It also includes bus gates for system components like the IOMMU and MSI-lite interfaces.

Also mark the ahb-store, mbus-store and ahb-cpus clocks as critical. Disabling either store gate breaks access to boot/storage devices such as MMC and SPI NOR, while gating ahb-cpus hangs any access to the CPUS power domain registers when unused clocks are disabled.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 501 ++++++++++++++++++++++++++++++++-
 1 file changed, 500 insertions(+), 1 deletion(-)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +500 -1
index 7847eec84313..c26b640fd257 100644
@@ -11,6 +11,10 @@
  *
  * CPU_PERI_CLK_REG has no documented consumer, while NSI_CLK_REG has no
  * known kernel consumer, so they are not modelled here.
+ *
+ * TODO: The real parents of some bus gates, including its-pcie0-aclk,
+ * msi-lite, npu, sgpio, lpc and i2spcm, are not documented in the
+ * manual. For now, follow the vendor BSP, which keeps them on hosc.
  */
 
 #include <linux/clk-provider.h>
@@ -454,16 +458,19 @@ static SUNXI_CCU_M_DATA_WITH_MUX(ahb_clk, "ahb", ahb_apb_parents, 0x500,
 				 0, 5,		/* M */
 				 24, 2,		/* mux */
 				 0);
+static const struct clk_hw *ahb_hws[] = { &ahb_clk.common.hw };
 
 static SUNXI_CCU_M_DATA_WITH_MUX(apb0_clk, "apb0", ahb_apb_parents, 0x510,
 				 0, 5,		/* M */
 				 24, 2,		/* mux */
 				 0);
+static const struct clk_hw *apb0_hws[] = { &apb0_clk.common.hw };
 
 static SUNXI_CCU_M_DATA_WITH_MUX(apb1_clk, "apb1", ahb_apb_parents, 0x518,
 				 0, 5,		/* M */
 				 24, 2,		/* mux */
 				 0);
+static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw };
 
 static const struct clk_parent_data apb_uart_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -476,6 +483,9 @@ static SUNXI_CCU_M_DATA_WITH_MUX(apb_uart_clk, "apb-uart", apb_uart_parents, 0x5
 				 0, 5,		/* M */
 				 24, 3,		/* mux */
 				 0);
+static const struct clk_hw *apb_uart_hws[] = {
+	&apb_uart_clk.common.hw
+};
 
 static const struct clk_parent_data trace_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -503,6 +513,8 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gic_clk, "gic", gic_parents, 0x560,
 				      BIT(31),	/* gate */
 				      CLK_IS_CRITICAL);
 
+static SUNXI_CCU_GATE_DATA(bus_its_pcie0_aclk_clk, "bus-its-pcie0-aclk", hosc, 0x574, BIT(1), 0);
+
 static const struct clk_parent_data mbus_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
 	{ .hw = &pll_periph1_600M_clk.hw },
@@ -517,9 +529,127 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588
 					   BIT(31),	/* gate */
 					   CLK_IS_CRITICAL,
 					   CCU_FEATURE_UPDATE_BIT);
+static const struct clk_hw *mbus_hws[] = { &mbus_clk.common.hw };
+
+static SUNXI_CCU_GATE_HWS(mbus_iommu0_sys_clk, "mbus-iommu0-sys", mbus_hws, 0x58c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(apb_iommu0_sys_clk, "apb-iommu0-sys", apb0_hws, 0x58c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(ahb_iommu0_sys_clk, "ahb-iommu0-sys", ahb_hws, 0x58c, BIT(2), 0);
+
+static SUNXI_CCU_GATE_DATA(bus_msi_lite0_clk, "bus-msi-lite0", hosc, 0x594, BIT(0), 0);
+static SUNXI_CCU_GATE_DATA(bus_msi_lite1_clk, "bus-msi-lite1", hosc, 0x59c, BIT(0), 0);
+static SUNXI_CCU_GATE_DATA(bus_msi_lite2_clk, "bus-msi-lite2", hosc, 0x5a4, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(mbus_iommu1_sys_clk, "mbus-iommu1-sys", mbus_hws, 0x5b4, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(apb_iommu1_sys_clk, "apb-iommu1-sys", apb0_hws, 0x5b4, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(ahb_iommu1_sys_clk, "ahb-iommu1-sys", ahb_hws, 0x5b4, BIT(2), 0);
+
+static SUNXI_CCU_GATE_HWS(ahb_ve_dec_clk, "ahb-ve-dec", ahb_hws,
+			  0x5c0, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(ahb_ve_enc_clk, "ahb-ve-enc", ahb_hws,
+			  0x5c0, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(ahb_vid_in_clk, "ahb-vid-in", ahb_hws,
+			  0x5c0, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(ahb_vid_cout0_clk, "ahb-vid-cout0", ahb_hws,
+			  0x5c0, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(ahb_vid_cout1_clk, "ahb-vid-cout1", ahb_hws,
+			  0x5c0, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(ahb_de_clk, "ahb-de", ahb_hws,
+			  0x5c0, BIT(5), 0);
+static SUNXI_CCU_GATE_HWS(ahb_npu_clk, "ahb-npu", ahb_hws,
+			  0x5c0, BIT(6), 0);
+static SUNXI_CCU_GATE_HWS(ahb_gpu0_clk, "ahb-gpu0", ahb_hws,
+			  0x5c0, BIT(7), 0);
+static SUNXI_CCU_GATE_HWS(ahb_serdes_clk, "ahb-serdes", ahb_hws,
+			  0x5c0, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(ahb_usb_sys_clk, "ahb-usb-sys", ahb_hws,
+			  0x5c0, BIT(9), 0);
+static SUNXI_CCU_GATE_HWS(ahb_msi_lite0_clk, "ahb-msi-lite0", ahb_hws,
+			  0x5c0, BIT(16), 0);
+
+/* This gate controls access to the storage controller MMIO registers. */
+static SUNXI_CCU_GATE_HWS(ahb_store_clk, "ahb-store", ahb_hws,
+			  0x5c0, BIT(24), 0);
+static const struct clk_hw *ahb_store_hws[] = { &ahb_store_clk.common.hw };
+
+/* Keep enabled for access to the CPUS domain registers. */
+static SUNXI_CCU_GATE_HWS(ahb_cpus_clk, "ahb-cpus", ahb_hws,
+			  0x5c0, BIT(28), CLK_IS_CRITICAL);
+
+static SUNXI_CCU_GATE_HWS(mbus_iommu0_clk, "mbus-iommu0", mbus_hws,
+			  0x5e0, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(mbus_iommu1_clk, "mbus-iommu1", mbus_hws,
+			  0x5e0, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(mbus_desys_clk, "mbus-desys", mbus_hws,
+			  0x5e0, BIT(11), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ve_enc0_gate_clk, "mbus-ve-enc0-gate", mbus_hws,
+			  0x5e0, BIT(12), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ve_dec0_gate_clk, "mbus-ve-dec0-gate", mbus_hws,
+			  0x5e0, BIT(14), 0);
+static SUNXI_CCU_GATE_HWS(mbus_gpu0_clk, "mbus-gpu0", mbus_hws,
+			  0x5e0, BIT(16), 0);
+static SUNXI_CCU_GATE_HWS(mbus_npu_clk, "mbus-npu", mbus_hws,
+			  0x5e0, BIT(18), 0);
+static SUNXI_CCU_GATE_HWS(mbus_vid_in_clk, "mbus-vid-in", mbus_hws,
+			  0x5e0, BIT(24), 0);
+static SUNXI_CCU_GATE_HWS(mbus_serdes_clk, "mbus-serdes", mbus_hws,
+			  0x5e0, BIT(28), 0);
+static SUNXI_CCU_GATE_HWS(mbus_msi_lite0_clk, "mbus-msi-lite0", mbus_hws,
+			  0x5e0, BIT(29), 0);
+
+/* Keep enabled for the storage controller DMA paths. */
+static SUNXI_CCU_GATE_HWS(mbus_store_clk, "mbus-store", mbus_hws,
+			  0x5e0, BIT(30), CLK_IS_CRITICAL);
+static const struct clk_hw *mbus_store_hws[] = { &mbus_store_clk.common.hw };
+
+static SUNXI_CCU_GATE_HWS(mbus_msi_lite2_clk, "mbus-msi-lite2", mbus_hws,
+			  0x5e0, BIT(31), 0);
+
+static SUNXI_CCU_GATE_HWS(mbus_dma0_clk, "mbus-dma0", mbus_hws,
+			  0x5e4, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ve_enc0_clk, "mbus-ve-enc0", mbus_hws,
+			  0x5e4, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ce_clk, "mbus-ce", mbus_hws,
+			  0x5e4, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(mbus_dma1_clk, "mbus-dma1", mbus_hws,
+			  0x5e4, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(mbus_nand0_clk, "mbus-nand0", mbus_store_hws,
+			  0x5e4, BIT(5), 0);
+static SUNXI_CCU_GATE_HWS(mbus_csi_clk, "mbus-csi", mbus_hws,
+			  0x5e4, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(mbus_isp_clk, "mbus-isp", mbus_hws,
+			  0x5e4, BIT(9), 0);
+static SUNXI_CCU_GATE_HWS(mbus_gmac0_clk, "mbus-gmac0", mbus_hws,
+			  0x5e4, BIT(11), 0);
+/* Undocumented, taken from the vendor kernel. */
+static SUNXI_CCU_GATE_HWS(mbus_gmac1_clk, "mbus-gmac1", mbus_hws,
+			  0x5e4, BIT(12), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ve_dec0_clk, "mbus-ve-dec0", mbus_hws,
+			  0x5e4, BIT(18), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dma0_clk, "bus-dma0", ahb_hws,
+			  0x704, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_dma1_clk, "bus-dma1", ahb_hws,
+			  0x70c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_spinlock_clk, "bus-spinlock", ahb_hws,
+			  0x724, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_msgbox0_clk, "bus-msgbox0", ahb_hws,
+			  0x744, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_pwm0_clk, "bus-pwm0", apb0_hws,
+			  0x784, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_pwm1_clk, "bus-pwm1", apb0_hws,
+			  0x78c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dbg_clk, "bus-dbg", sys_24M_hws,
+			  0x7a4, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_sysdap_clk, "bus-sysdap", apb1_hws,
+			  0x7ac, BIT(0), 0);
 
 /**************************************************************************
- *                          mod clocks                                    *
+ *                          mod clocks with gates                         *
  **************************************************************************/
 
 static const struct clk_parent_data timer_parents[] = {
@@ -579,6 +709,7 @@ static SUNXI_CCU_P_DATA_WITH_MUX_GATE(timer9_clk, "timer9", timer_parents, 0x824
 				      24, 3,		/* mux */
 				      BIT(31),		/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_timer_clk, "bus-timer", ahb_hws, 0x850, BIT(0), 0);
 
 /* Undocumented, taken from the vendor kernel. */
 static const struct clk_parent_data avs_parents[] = {
@@ -604,6 +735,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(de0_clk, "de0", de_parents, 0xa00,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE_HWS(bus_de0_clk, "bus-de0", ahb_hws, 0xa04, BIT(0), 0);
 
 static const struct clk_hw *di_parents[] = {
 	&pll_periph0_600M_clk.hw,
@@ -617,6 +749,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", di_parents, 0xa20,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE_HWS(bus_di_clk, "bus-di", ahb_hws, 0xa24, BIT(0), 0);
 
 static const struct clk_hw *g2d_parents[] = {
 	&pll_periph0_400M_clk.hw,
@@ -629,6 +762,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", g2d_parents, 0xa40,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE_HWS(bus_g2d_clk, "bus-g2d", ahb_hws, 0xa44, BIT(0), 0);
 
 static const struct clk_hw *eink_parents[] = {
 	&pll_periph0_480M_clk.common.hw,
@@ -652,6 +786,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(eink_panel_clk, "eink-panel", eink_panel_par
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE_HWS(bus_eink_clk, "bus-eink", ahb_hws, 0xa6c, BIT(0), 0);
 
 static const struct clk_hw *ve_enc_parents[] = {
 	&pll_ve0_clk.common.hw,
@@ -683,6 +818,9 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_dec0_clk, "ve-dec0", ve_dec_parents, 0xa8
 				    BIT(31),	/* gate */
 				    CLK_SET_RATE_PARENT);
 
+static SUNXI_CCU_GATE_HWS(bus_ve_enc0_clk, "bus-ve-enc0", ahb_hws, 0xa8c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_ve_dec0_clk, "bus-ve-dec0", ahb_hws, 0xa8c, BIT(2), 0);
+
 static const struct clk_hw *ce_parents[] = {
 	&sys_24M_clk.hw,
 	&pll_periph0_400M_clk.hw,
@@ -693,6 +831,8 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0xac0,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_ce_clk, "bus-ce", ahb_hws, 0xac4, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_ce_sys_clk, "bus-ce-sys", ahb_hws, 0xac4, BIT(1), 0);
 
 static const struct clk_hw *npu_parents[] = {
 	&pll_npu_clk.common.hw,
@@ -708,6 +848,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(npu_clk, "npu", npu_parents, 0xb00,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_npu_clk, "bus-npu", hosc, 0xb04, BIT(0), 0);
 
 /*
  * GPU_CLK = ClockSource * ((16 - M) / 16)
@@ -740,6 +881,7 @@ static struct ccu_div gpu0_clk = {
 							   &ccu_div_ops, 0),
 	}
 };
+static SUNXI_CCU_GATE_HWS(bus_gpu0_clk, "bus-gpu0", ahb_hws, 0xb24, BIT(0), 0);
 
 static const struct clk_parent_data dram_parents[] = {
 	{ .hw = &pll_ddr_clk.common.hw, },
@@ -754,6 +896,8 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(dram0_clk, "dram0", dram_parents, 0xc
 					   BIT(31),	/* gate */
 					   CLK_IS_CRITICAL,
 					   CCU_FEATURE_UPDATE_BIT);
+static SUNXI_CCU_GATE_HWS(bus_dram0_clk, "bus-dram0", ahb_hws, 0xc0c,
+			  BIT(0), CLK_IS_CRITICAL);
 
 static const struct clk_parent_data nand_mmc_parents[] = {
 	{ .hw = &sys_24M_clk.hw, },
@@ -772,6 +916,7 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(nand0_clk1_clk, "nand0-clk1", nand_mmc_par
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_nand0_clk, "bus-nand0", ahb_store_hws, 0xc8c, BIT(0), 0);
 
 static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc0_clk, "mmc0", nand_mmc_parents, 0xd00,
 					     0, 5,	/* M */
@@ -780,6 +925,8 @@ static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc0_clk, "mmc0", nand_mmc_parents,
 					     BIT(31),	/* gate */
 					     2,		/* post div */
 					     0);
+static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", ahb_store_hws, 0xd0c, BIT(0), 0);
+
 static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc1_clk, "mmc1", nand_mmc_parents, 0xd10,
 					     0, 5,	/* M */
 					     8, 5,	/* P */
@@ -787,6 +934,7 @@ static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc1_clk, "mmc1", nand_mmc_parents,
 					     BIT(31),	/* gate */
 					     2,		/* post div */
 					     0);
+static SUNXI_CCU_GATE_HWS(bus_mmc1_clk, "bus-mmc1", ahb_store_hws, 0xd1c, BIT(0), 0);
 
 static const struct clk_parent_data mmc2_mmc3_parents[] = {
 	{ .hw = &sys_24M_clk.hw, },
@@ -802,6 +950,8 @@ static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc2_clk, "mmc2", mmc2_mmc3_parents
 					     BIT(31),	/* gate */
 					     2,		/* post div */
 					     0);
+static SUNXI_CCU_GATE_HWS(bus_mmc2_clk, "bus-mmc2", ahb_store_hws, 0xd2c, BIT(0), 0);
+
 static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc3_clk, "mmc3", mmc2_mmc3_parents, 0xd30,
 					     0, 5,	/* M */
 					     8, 5,	/* P */
@@ -809,6 +959,7 @@ static SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(mmc3_clk, "mmc3", mmc2_mmc3_parents
 					     BIT(31),	/* gate */
 					     2,		/* post div */
 					     0);
+static SUNXI_CCU_GATE_HWS(bus_mmc3_clk, "bus-mmc3", ahb_store_hws, 0xd3c, BIT(0), 0);
 
 static const struct clk_hw *ufs_axi_parents[] = {
 	&pll_periph0_300M_clk.hw,
@@ -829,6 +980,29 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ufs_cfg_clk, "ufs-cfg", ufs_cfg_parents, 0
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_ufs_clk, "bus-ufs", ahb_store_hws, 0xd8c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb_uart_hws, 0xe00, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb_uart_hws, 0xe04, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb_uart_hws, 0xe08, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb_uart_hws, 0xe0c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart4_clk, "bus-uart4", apb_uart_hws, 0xe10, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart5_clk, "bus-uart5", apb_uart_hws, 0xe14, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart6_clk, "bus-uart6", apb_uart_hws, 0xe18, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_i2c0_clk, "bus-i2c0", apb1_hws, 0xe80, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c1_clk, "bus-i2c1", apb1_hws, 0xe84, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws, 0xe88, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws, 0xe8c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c4_clk, "bus-i2c4", apb1_hws, 0xe90, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c5_clk, "bus-i2c5", apb1_hws, 0xe94, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c6_clk, "bus-i2c6", apb1_hws, 0xe98, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c7_clk, "bus-i2c7", apb1_hws, 0xe9c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c8_clk, "bus-i2c8", apb1_hws, 0xea0, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c9_clk, "bus-i2c9", apb1_hws, 0xea4, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c10_clk, "bus-i2c10", apb1_hws, 0xea8, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c11_clk, "bus-i2c11", apb1_hws, 0xeac, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c12_clk, "bus-i2c12", apb1_hws, 0xeb0, BIT(0), 0);
 
 static const struct clk_parent_data spi_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -846,18 +1020,23 @@ static SUNXI_CCU_DUALDIV_MUX_GATE(spi0_clk, "spi0", spi_parents, 0xf00,
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", ahb_store_hws, 0xf04, BIT(0), 0);
+
 static SUNXI_CCU_DUALDIV_MUX_GATE(spi1_clk, "spi1", spi_parents, 0xf08,
 				  0, 5,		/* M */
 				  8, 5,		/* N */
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", ahb_store_hws, 0xf0c, BIT(0), 0);
+
 static SUNXI_CCU_DUALDIV_MUX_GATE(spi2_clk, "spi2", spi_parents, 0xf10,
 				  0, 5,		/* M */
 				  8, 5,		/* N */
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spi2_clk, "bus-spi2", ahb_store_hws, 0xf14, BIT(0), 0);
 
 static const struct clk_parent_data spif_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -875,12 +1054,16 @@ static SUNXI_CCU_DUALDIV_MUX_GATE(spif_clk, "spif", spif_parents, 0xf18,
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spif_clk, "bus-spif", ahb_store_hws, 0xf1c, BIT(0), 0);
+
 static SUNXI_CCU_DUALDIV_MUX_GATE(spi3_clk, "spi3", spi_parents, 0xf20,
 				  0, 5,		/* M */
 				  8, 5,		/* N */
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spi3_clk, "bus-spi3", ahb_store_hws, 0xf24, BIT(0), 0);
+
 /* Undocumented, taken from the vendor kernel. */
 static SUNXI_CCU_DUALDIV_MUX_GATE(spi4_clk, "spi4", spi_parents, 0xf28,
 				  0, 5,		/* M */
@@ -888,6 +1071,7 @@ static SUNXI_CCU_DUALDIV_MUX_GATE(spi4_clk, "spi4", spi_parents, 0xf28,
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_spi4_clk, "bus-spi4", ahb_store_hws, 0xf2c, BIT(0), 0);
 
 static const struct clk_parent_data gpadc0_24m_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -898,6 +1082,9 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(gpadc0_24m_clk, "gpadc0-24m", gpadc0_24m_p
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_gpadc0_clk, "bus-gpadc0", ahb_hws, 0xfc4, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_ths0_clk, "bus-ths0", apb0_hws, 0xfe4, BIT(0), 0);
 
 static const struct clk_parent_data irrx_parents[] = {
 	{ .fw_name = "losc"},
@@ -909,6 +1096,7 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irrx_clk, "irrx", irrx_parents, 0x1000,
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_irrx_clk, "bus-irrx", apb0_hws, 0x1004, BIT(0), 0);
 
 static const struct clk_parent_data irtx_parents[] = {
 	{ .fw_name = "losc"},
@@ -920,6 +1108,9 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(irtx_clk, "irtx", irtx_parents, 0x1008,
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_irtx_clk, "bus-irtx", apb0_hws, 0x100c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_lradc_clk, "bus-lradc", apb0_hws, 0x1024, BIT(0), 0);
 
 /* Undocumented, taken from the vendor kernel. */
 static const struct clk_parent_data sgpio_parents[] = {
@@ -931,6 +1122,7 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(sgpio_clk, "sgpio", sgpio_parents, 0x1060,
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_DATA(bus_sgpio_clk, "bus-sgpio", hosc, 0x1064, BIT(0), 0);
 
 /* Undocumented, taken from the vendor kernel. */
 static const struct clk_hw *lpc_parents[] = {
@@ -944,6 +1136,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(lpc_clk, "lpc", lpc_parents, 0x1080,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_lpc_clk, "bus-lpc", hosc, 0x1084, BIT(0), 0);
 
 static const struct clk_hw *i2spcm_parents[] = {
 	&pll_audio0_4x_clk.common.hw,
@@ -956,11 +1149,15 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm0_clk, "i2spcm0", i2spcm_parents, 0x12
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_i2spcm0_clk, "bus-i2spcm0", hosc, 0x120c, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm1_clk, "i2spcm1", i2spcm_parents, 0x1210,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_i2spcm1_clk, "bus-i2spcm1", hosc, 0x121c, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_clk, "i2spcm2", i2spcm_parents, 0x1220,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
@@ -979,16 +1176,22 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm2_asrc_clk, "i2spcm2_asrc", i2spcm2_as
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+
+static SUNXI_CCU_GATE_DATA(bus_i2spcm2_clk, "bus-i2spcm2", hosc, 0x122c, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm3_clk, "i2spcm3", i2spcm_parents, 0x1230,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_i2spcm3_clk, "bus-i2spcm3", hosc, 0x123c, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2spcm4_clk, "i2spcm4", i2spcm_parents, 0x1240,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_DATA(bus_i2spcm4_clk, "bus-i2spcm4", hosc, 0x124c, BIT(0), 0);
 
 static const struct clk_hw *spdif_tx_parents[] = {
 	&pll_audio0_4x_clk.common.hw,
@@ -1012,6 +1215,8 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents,
 				    BIT(31),	/* gate */
 				    0);
 
+static SUNXI_CCU_GATE_HWS(bus_spdif_clk, "bus-spdif", apb1_hws, 0x128c, BIT(0), 0);
+
 static const struct clk_hw *dmic_parents[] = {
 	&pll_audio0_4x_clk.common.hw,
 	&pll_audio1_div2_clk.hw,
@@ -1023,6 +1228,8 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_parents, 0x12c0,
 				    BIT(31),	/* gate */
 				    0);
 
+static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", apb1_hws, 0x12cc, BIT(0), 0);
+
 /*
  * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is
  * a 2x multiplier from pll-ref synchronized by pll-periph0, and is also used by
@@ -1054,6 +1261,9 @@ static struct ccu_mux usb_ohci0_clk = {
 							   &ccu_mux_ops, 0),
 	},
 };
+static SUNXI_CCU_GATE_HWS(bus_ohci0_clk, "bus-ohci0", ahb_hws, 0x1304, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_ehci0_clk, "bus-ehci0", ahb_hws, 0x1304, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(bus_otg_clk, "bus-otg", ahb_hws, 0x1304, BIT(8), 0);
 
 static struct ccu_mux usb_ohci1_clk = {
 	.enable		= BIT(31),
@@ -1070,6 +1280,8 @@ static struct ccu_mux usb_ohci1_clk = {
 							   &ccu_mux_ops, 0),
 	},
 };
+static SUNXI_CCU_GATE_HWS(bus_ohci1_clk, "bus-ohci1", ahb_hws, 0x130c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_ehci1_clk, "bus-ehci1", ahb_hws, 0x130c, BIT(4), 0);
 
 static const struct clk_parent_data usb01_ref_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -1172,11 +1384,14 @@ static SUNXI_CCU_M_HWS_WITH_GATE(gmac0_phy_clk, "gmac0-phy", pll_periph0_150M_hw
 				 0, 5,		/* M */
 				 BIT(31),	/* gate */
 				 0);
+static SUNXI_CCU_GATE_HWS(bus_gmac0_clk, "bus-gmac0", ahb_hws, 0x141c, BIT(0), 0);
+
 /* Undocumented, taken from the vendor kernel. */
 static SUNXI_CCU_M_HWS_WITH_GATE(gmac1_phy_clk, "gmac1-phy", pll_periph0_150M_hws, 0x1420,
 				 0, 5,		/* M */
 				 BIT(31),	/* gate */
 				 0);
+static SUNXI_CCU_GATE_HWS(bus_gmac1_clk, "bus-gmac1", ahb_hws, 0x142c, BIT(0), 0);
 
 static const struct clk_hw *tcon_lcd_parents[] = {
 	&pll_video0_4x_clk.common.hw,
@@ -1189,17 +1404,22 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_lcd_parents
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_tcon_lcd0_clk, "bus-tcon-lcd0", ahb_hws, 0x1504, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_lcd_parents, 0x1508,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_tcon_lcd1_clk, "bus-tcon-lcd1", ahb_hws, 0x150c, BIT(0), 0);
+
 /* Undocumented, taken from the vendor kernel. */
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(tcon_lcd2_clk, "tcon-lcd2", tcon_lcd_parents, 0x1510,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_tcon_lcd2_clk, "bus-tcon-lcd2", ahb_hws, 0x1514, BIT(0), 0);
 
 static const struct clk_hw *dsi_parents[] = {
 	&sys_24M_clk.hw,
@@ -1211,11 +1431,14 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi0_clk, "dsi0", dsi_parents, 0x1580,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_dsi0_clk, "bus-dsi0", ahb_hws, 0x1584, BIT(0), 0);
+
 static SUNXI_CCU_M_HW_WITH_MUX_GATE(dsi1_clk, "dsi1", dsi_parents, 0x1588,
 				    0, 5,	/* M */
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_dsi1_clk, "bus-dsi1", ahb_hws, 0x158c, BIT(0), 0);
 
 static const struct clk_hw *combphy_parents[] = {
 	&pll_video0_4x_clk.common.hw,
@@ -1235,6 +1458,9 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(combphy1_clk, "combphy1", combphy_parents, 0
 				    BIT(31),	/* gate */
 				    0);
 
+static SUNXI_CCU_GATE_HWS(bus_tcon_tv0_clk, "bus-tcon-tv0", ahb_hws, 0x1604, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_tcon_tv1_clk, "bus-tcon-tv1", ahb_hws, 0x160c, BIT(0), 0);
+
 static const struct clk_hw *edp_tv_parents[] = {
 	&pll_video0_4x_clk.common.hw,
 	&pll_video1_4x_clk.common.hw,
@@ -1246,6 +1472,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(edp_tv_clk, "edp-tv", edp_tv_parents, 0x1640
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_edp_tv_clk, "bus-edp-tv", ahb_hws, 0x164c, BIT(0), 0);
 
 static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k", pll_periph0_2x_hws, 0x1680,
 				      BIT(30),	/* gate */
@@ -1273,6 +1500,7 @@ static SUNXI_CCU_DUALDIV_MUX_GATE(hdmi_tv_clk, "hdmi-tv", hdmi_tv_parents, 0x168
 				  24, 3,	/* mux */
 				  BIT(31),	/* gate */
 				  0);
+static SUNXI_CCU_GATE_HWS(bus_hdmi_tv_clk, "bus-hdmi-tv", ahb_hws, 0x168c, BIT(0), 0);
 
 static const struct clk_parent_data hdmi_sfr_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -1285,6 +1513,9 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_sfr_clk, "hdmi-sfr", hdmi_sfr_parents,
 
 static SUNXI_CCU_GATE_HWS(hdcp_esm_clk, "hdcp-esm", pll_periph0_300M_hws, 0x1694, BIT(31), 0);
 
+static SUNXI_CCU_GATE_HWS(bus_dpss_top0_clk, "bus-dpss-top0", ahb_hws, 0x16c4, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_dpss_top1_clk, "bus-dpss-top1", ahb_hws, 0x16cc, BIT(0), 0);
+
 static const struct clk_parent_data ledc_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
 	{ .hw = &pll_periph0_600M_clk.hw },
@@ -1295,6 +1526,9 @@ static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ledc_parents, 0x1700,
 				      24, 3,	/* mux */
 				      BIT(31),	/* gate */
 				      0);
+static SUNXI_CCU_GATE_HWS(bus_ledc_clk, "bus-ledc", apb0_hws, 0x1704, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dsc_clk, "bus-dsc", ahb_hws, 0x1744, BIT(0), 0);
 
 static const struct clk_parent_data csi_master_parents[] = {
 	{ .hw = &sys_24M_clk.hw },
@@ -1336,6 +1570,7 @@ static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_clk, "csi", csi_parents, 0x1840,
 				    24, 3,	/* mux */
 				    BIT(31),	/* gate */
 				    0);
+static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", ahb_hws, 0x1844, BIT(0), 0);
 
 static const struct clk_hw *isp_parents[] = {
 	&pll_video2_4x_clk.common.hw,
@@ -1464,7 +1699,60 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
 	&apb_uart_clk.common,
 	&trace_clk.common,
 	&gic_clk.common,
+	&bus_its_pcie0_aclk_clk.common,
 	&mbus_clk.common,
+	&mbus_iommu0_sys_clk.common,
+	&apb_iommu0_sys_clk.common,
+	&ahb_iommu0_sys_clk.common,
+	&bus_msi_lite0_clk.common,
+	&bus_msi_lite1_clk.common,
+	&bus_msi_lite2_clk.common,
+	&mbus_iommu1_sys_clk.common,
+	&apb_iommu1_sys_clk.common,
+	&ahb_iommu1_sys_clk.common,
+	&ahb_ve_dec_clk.common,
+	&ahb_ve_enc_clk.common,
+	&ahb_vid_in_clk.common,
+	&ahb_vid_cout0_clk.common,
+	&ahb_vid_cout1_clk.common,
+	&ahb_de_clk.common,
+	&ahb_npu_clk.common,
+	&ahb_gpu0_clk.common,
+	&ahb_serdes_clk.common,
+	&ahb_usb_sys_clk.common,
+	&ahb_msi_lite0_clk.common,
+	&ahb_store_clk.common,
+	&ahb_cpus_clk.common,
+	&mbus_iommu0_clk.common,
+	&mbus_iommu1_clk.common,
+	&mbus_desys_clk.common,
+	&mbus_ve_enc0_gate_clk.common,
+	&mbus_ve_dec0_gate_clk.common,
+	&mbus_gpu0_clk.common,
+	&mbus_npu_clk.common,
+	&mbus_vid_in_clk.common,
+	&mbus_serdes_clk.common,
+	&mbus_msi_lite0_clk.common,
+	&mbus_store_clk.common,
+	&mbus_msi_lite2_clk.common,
+	&mbus_dma0_clk.common,
+	&mbus_ve_enc0_clk.common,
+	&mbus_ce_clk.common,
+	&mbus_dma1_clk.common,
+	&mbus_nand0_clk.common,
+	&mbus_csi_clk.common,
+	&mbus_isp_clk.common,
+	&mbus_gmac0_clk.common,
+	&mbus_gmac1_clk.common,
+	&mbus_ve_dec0_clk.common,
+	&bus_dma0_clk.common,
+	&bus_dma1_clk.common,
+	&bus_spinlock_clk.common,
+	&bus_msgbox0_clk.common,
+	&bus_pwm0_clk.common,
+	&bus_pwm1_clk.common,
+	&bus_dbg_clk.common,
+	&bus_sysdap_clk.common,
 	&timer0_clk.common,
 	&timer1_clk.common,
 	&timer2_clk.common,
@@ -1475,48 +1763,111 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
 	&timer7_clk.common,
 	&timer8_clk.common,
 	&timer9_clk.common,
+	&bus_timer_clk.common,
 	&avs_clk.common,
 	&de0_clk.common,
+	&bus_de0_clk.common,
 	&di_clk.common,
+	&bus_di_clk.common,
 	&g2d_clk.common,
+	&bus_g2d_clk.common,
 	&eink_clk.common,
 	&eink_panel_clk.common,
+	&bus_eink_clk.common,
 	&ve_enc0_clk.common,
 	&ve_dec0_clk.common,
+	&bus_ve_enc0_clk.common,
+	&bus_ve_dec0_clk.common,
 	&ce_clk.common,
+	&bus_ce_clk.common,
+	&bus_ce_sys_clk.common,
 	&npu_clk.common,
+	&bus_npu_clk.common,
 	&gpu0_clk.common,
+	&bus_gpu0_clk.common,
 	&dram0_clk.common,
+	&bus_dram0_clk.common,
 	&nand0_clk0_clk.common,
 	&nand0_clk1_clk.common,
+	&bus_nand0_clk.common,
 	&mmc0_clk.common,
+	&bus_mmc0_clk.common,
 	&mmc1_clk.common,
+	&bus_mmc1_clk.common,
 	&mmc2_clk.common,
+	&bus_mmc2_clk.common,
 	&mmc3_clk.common,
+	&bus_mmc3_clk.common,
 	&ufs_axi_clk.common,
 	&ufs_cfg_clk.common,
+	&bus_ufs_clk.common,
+	&bus_uart0_clk.common,
+	&bus_uart1_clk.common,
+	&bus_uart2_clk.common,
+	&bus_uart3_clk.common,
+	&bus_uart4_clk.common,
+	&bus_uart5_clk.common,
+	&bus_uart6_clk.common,
+	&bus_i2c0_clk.common,
+	&bus_i2c1_clk.common,
+	&bus_i2c2_clk.common,
+	&bus_i2c3_clk.common,
+	&bus_i2c4_clk.common,
+	&bus_i2c5_clk.common,
+	&bus_i2c6_clk.common,
+	&bus_i2c7_clk.common,
+	&bus_i2c8_clk.common,
+	&bus_i2c9_clk.common,
+	&bus_i2c10_clk.common,
+	&bus_i2c11_clk.common,
+	&bus_i2c12_clk.common,
 	&spi0_clk.common,
+	&bus_spi0_clk.common,
 	&spi1_clk.common,
+	&bus_spi1_clk.common,
 	&spi2_clk.common,
+	&bus_spi2_clk.common,
 	&spif_clk.common,
+	&bus_spif_clk.common,
 	&spi3_clk.common,
+	&bus_spi3_clk.common,
 	&spi4_clk.common,
+	&bus_spi4_clk.common,
 	&gpadc0_24m_clk.common,
+	&bus_gpadc0_clk.common,
+	&bus_ths0_clk.common,
 	&irrx_clk.common,
+	&bus_irrx_clk.common,
 	&irtx_clk.common,
+	&bus_irtx_clk.common,
+	&bus_lradc_clk.common,
 	&sgpio_clk.common,
+	&bus_sgpio_clk.common,
 	&lpc_clk.common,
+	&bus_lpc_clk.common,
 	&i2spcm0_clk.common,
+	&bus_i2spcm0_clk.common,
 	&i2spcm1_clk.common,
+	&bus_i2spcm1_clk.common,
 	&i2spcm2_clk.common,
 	&i2spcm2_asrc_clk.common,
+	&bus_i2spcm2_clk.common,
 	&i2spcm3_clk.common,
+	&bus_i2spcm3_clk.common,
 	&i2spcm4_clk.common,
+	&bus_i2spcm4_clk.common,
 	&spdif_tx_clk.common,
 	&spdif_rx_clk.common,
+	&bus_spdif_clk.common,
 	&dmic_clk.common,
+	&bus_dmic_clk.common,
 	&usb_ohci0_clk.common,
+	&bus_ohci0_clk.common,
+	&bus_ehci0_clk.common,
+	&bus_otg_clk.common,
 	&usb_ohci1_clk.common,
+	&bus_ohci1_clk.common,
+	&bus_ehci1_clk.common,
 	&usb01_ref_clk.common,
 	&usb2_u2_ref_clk.common,
 	&usb2_suspend_clk.common,
@@ -1528,25 +1879,41 @@ static struct ccu_common *sun60i_a733_ccu_clks[] = {
 	&serdes_phy_clk.common,
 	&gmac_ptp_clk.common,
 	&gmac0_phy_clk.common,
+	&bus_gmac0_clk.common,
 	&gmac1_phy_clk.common,
+	&bus_gmac1_clk.common,
 	&tcon_lcd0_clk.common,
+	&bus_tcon_lcd0_clk.common,
 	&tcon_lcd1_clk.common,
+	&bus_tcon_lcd1_clk.common,
 	&tcon_lcd2_clk.common,
+	&bus_tcon_lcd2_clk.common,
 	&dsi0_clk.common,
+	&bus_dsi0_clk.common,
 	&dsi1_clk.common,
+	&bus_dsi1_clk.common,
 	&combphy0_clk.common,
 	&combphy1_clk.common,
+	&bus_tcon_tv0_clk.common,
+	&bus_tcon_tv1_clk.common,
 	&edp_tv_clk.common,
+	&bus_edp_tv_clk.common,
 	&hdmi_cec_32k_clk.common,
 	&hdmi_cec_clk.common,
 	&hdmi_tv_clk.common,
+	&bus_hdmi_tv_clk.common,
 	&hdmi_sfr_clk.common,
 	&hdcp_esm_clk.common,
+	&bus_dpss_top0_clk.common,
+	&bus_dpss_top1_clk.common,
 	&ledc_clk.common,
+	&bus_ledc_clk.common,
+	&bus_dsc_clk.common,
 	&csi_master0_clk.common,
 	&csi_master1_clk.common,
 	&csi_master2_clk.common,
 	&csi_clk.common,
+	&bus_csi_clk.common,
 	&isp_clk.common,
 	&res_dcap_24m_clk.common,
 	&apb2jtag_clk.common,
@@ -1613,7 +1980,60 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 		[CLK_APB_UART]		= &apb_uart_clk.common.hw,
 		[CLK_TRACE]		= &trace_clk.common.hw,
 		[CLK_GIC]		= &gic_clk.common.hw,
+		[CLK_BUS_ITS_PCIE0_ACLK] = &bus_its_pcie0_aclk_clk.common.hw,
 		[CLK_MBUS]		= &mbus_clk.common.hw,
+		[CLK_MBUS_IOMMU0_SYS]	= &mbus_iommu0_sys_clk.common.hw,
+		[CLK_APB_IOMMU0_SYS]	= &apb_iommu0_sys_clk.common.hw,
+		[CLK_AHB_IOMMU0_SYS]	= &ahb_iommu0_sys_clk.common.hw,
+		[CLK_BUS_MSI_LITE0]	= &bus_msi_lite0_clk.common.hw,
+		[CLK_BUS_MSI_LITE1]	= &bus_msi_lite1_clk.common.hw,
+		[CLK_BUS_MSI_LITE2]	= &bus_msi_lite2_clk.common.hw,
+		[CLK_MBUS_IOMMU1_SYS]	= &mbus_iommu1_sys_clk.common.hw,
+		[CLK_APB_IOMMU1_SYS]	= &apb_iommu1_sys_clk.common.hw,
+		[CLK_AHB_IOMMU1_SYS]	= &ahb_iommu1_sys_clk.common.hw,
+		[CLK_AHB_VE_DEC]	= &ahb_ve_dec_clk.common.hw,
+		[CLK_AHB_VE_ENC]	= &ahb_ve_enc_clk.common.hw,
+		[CLK_AHB_VID_IN]	= &ahb_vid_in_clk.common.hw,
+		[CLK_AHB_VID_COUT0]	= &ahb_vid_cout0_clk.common.hw,
+		[CLK_AHB_VID_COUT1]	= &ahb_vid_cout1_clk.common.hw,
+		[CLK_AHB_DE]		= &ahb_de_clk.common.hw,
+		[CLK_AHB_NPU]		= &ahb_npu_clk.common.hw,
+		[CLK_AHB_GPU0]		= &ahb_gpu0_clk.common.hw,
+		[CLK_AHB_SERDES]	= &ahb_serdes_clk.common.hw,
+		[CLK_AHB_USB_SYS]	= &ahb_usb_sys_clk.common.hw,
+		[CLK_AHB_MSI_LITE0]	= &ahb_msi_lite0_clk.common.hw,
+		[CLK_AHB_STORE]		= &ahb_store_clk.common.hw,
+		[CLK_AHB_CPUS]		= &ahb_cpus_clk.common.hw,
+		[CLK_MBUS_IOMMU0]	= &mbus_iommu0_clk.common.hw,
+		[CLK_MBUS_IOMMU1]	= &mbus_iommu1_clk.common.hw,
+		[CLK_MBUS_DESYS]	= &mbus_desys_clk.common.hw,
+		[CLK_MBUS_VE_ENC0_GATE]	= &mbus_ve_enc0_gate_clk.common.hw,
+		[CLK_MBUS_VE_DEC0_GATE]	= &mbus_ve_dec0_gate_clk.common.hw,
+		[CLK_MBUS_GPU0]		= &mbus_gpu0_clk.common.hw,
+		[CLK_MBUS_NPU]		= &mbus_npu_clk.common.hw,
+		[CLK_MBUS_VID_IN]	= &mbus_vid_in_clk.common.hw,
+		[CLK_MBUS_SERDES]	= &mbus_serdes_clk.common.hw,
+		[CLK_MBUS_MSI_LITE0]	= &mbus_msi_lite0_clk.common.hw,
+		[CLK_MBUS_STORE]	= &mbus_store_clk.common.hw,
+		[CLK_MBUS_MSI_LITE2]	= &mbus_msi_lite2_clk.common.hw,
+		[CLK_MBUS_DMA0]		= &mbus_dma0_clk.common.hw,
+		[CLK_MBUS_VE_ENC0]	= &mbus_ve_enc0_clk.common.hw,
+		[CLK_MBUS_CE]		= &mbus_ce_clk.common.hw,
+		[CLK_MBUS_DMA1]		= &mbus_dma1_clk.common.hw,
+		[CLK_MBUS_NAND0]	= &mbus_nand0_clk.common.hw,
+		[CLK_MBUS_CSI]		= &mbus_csi_clk.common.hw,
+		[CLK_MBUS_ISP]		= &mbus_isp_clk.common.hw,
+		[CLK_MBUS_GMAC0]	= &mbus_gmac0_clk.common.hw,
+		[CLK_MBUS_GMAC1]	= &mbus_gmac1_clk.common.hw,
+		[CLK_MBUS_VE_DEC0]	= &mbus_ve_dec0_clk.common.hw,
+		[CLK_BUS_DMA0]		= &bus_dma0_clk.common.hw,
+		[CLK_BUS_DMA1]		= &bus_dma1_clk.common.hw,
+		[CLK_BUS_SPINLOCK]	= &bus_spinlock_clk.common.hw,
+		[CLK_BUS_MSGBOX0]	= &bus_msgbox0_clk.common.hw,
+		[CLK_BUS_PWM0]		= &bus_pwm0_clk.common.hw,
+		[CLK_BUS_PWM1]		= &bus_pwm1_clk.common.hw,
+		[CLK_BUS_DBG]		= &bus_dbg_clk.common.hw,
+		[CLK_BUS_SYSDAP]	= &bus_sysdap_clk.common.hw,
 		[CLK_TIMER0]		= &timer0_clk.common.hw,
 		[CLK_TIMER1]		= &timer1_clk.common.hw,
 		[CLK_TIMER2]		= &timer2_clk.common.hw,
@@ -1624,48 +2044,111 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 		[CLK_TIMER7]		= &timer7_clk.common.hw,
 		[CLK_TIMER8]		= &timer8_clk.common.hw,
 		[CLK_TIMER9]		= &timer9_clk.common.hw,
+		[CLK_BUS_TIMER]		= &bus_timer_clk.common.hw,
 		[CLK_AVS]		= &avs_clk.common.hw,
 		[CLK_DE0]		= &de0_clk.common.hw,
+		[CLK_BUS_DE0]		= &bus_de0_clk.common.hw,
 		[CLK_DI]		= &di_clk.common.hw,
+		[CLK_BUS_DI]		= &bus_di_clk.common.hw,
 		[CLK_G2D]		= &g2d_clk.common.hw,
+		[CLK_BUS_G2D]		= &bus_g2d_clk.common.hw,
 		[CLK_EINK]		= &eink_clk.common.hw,
 		[CLK_EINK_PANEL]	= &eink_panel_clk.common.hw,
+		[CLK_BUS_EINK]		= &bus_eink_clk.common.hw,
 		[CLK_VE_ENC0]		= &ve_enc0_clk.common.hw,
 		[CLK_VE_DEC0]		= &ve_dec0_clk.common.hw,
+		[CLK_BUS_VE_ENC0]	= &bus_ve_enc0_clk.common.hw,
+		[CLK_BUS_VE_DEC0]	= &bus_ve_dec0_clk.common.hw,
 		[CLK_CE]		= &ce_clk.common.hw,
+		[CLK_BUS_CE]		= &bus_ce_clk.common.hw,
+		[CLK_BUS_CE_SYS]	= &bus_ce_sys_clk.common.hw,
 		[CLK_NPU]		= &npu_clk.common.hw,
+		[CLK_BUS_NPU]		= &bus_npu_clk.common.hw,
 		[CLK_GPU0]		= &gpu0_clk.common.hw,
+		[CLK_BUS_GPU0]		= &bus_gpu0_clk.common.hw,
 		[CLK_DRAM0]		= &dram0_clk.common.hw,
+		[CLK_BUS_DRAM0]		= &bus_dram0_clk.common.hw,
 		[CLK_NAND0_CLK0]	= &nand0_clk0_clk.common.hw,
 		[CLK_NAND0_CLK1]	= &nand0_clk1_clk.common.hw,
+		[CLK_BUS_NAND0]		= &bus_nand0_clk.common.hw,
 		[CLK_MMC0]		= &mmc0_clk.common.hw,
+		[CLK_BUS_MMC0]		= &bus_mmc0_clk.common.hw,
 		[CLK_MMC1]		= &mmc1_clk.common.hw,
+		[CLK_BUS_MMC1]		= &bus_mmc1_clk.common.hw,
 		[CLK_MMC2]		= &mmc2_clk.common.hw,
+		[CLK_BUS_MMC2]		= &bus_mmc2_clk.common.hw,
 		[CLK_MMC3]		= &mmc3_clk.common.hw,
+		[CLK_BUS_MMC3]		= &bus_mmc3_clk.common.hw,
 		[CLK_UFS_AXI]		= &ufs_axi_clk.common.hw,
 		[CLK_UFS_CFG]		= &ufs_cfg_clk.common.hw,
+		[CLK_BUS_UFS]		= &bus_ufs_clk.common.hw,
+		[CLK_BUS_UART0]		= &bus_uart0_clk.common.hw,
+		[CLK_BUS_UART1]		= &bus_uart1_clk.common.hw,
+		[CLK_BUS_UART2]		= &bus_uart2_clk.common.hw,
+		[CLK_BUS_UART3]		= &bus_uart3_clk.common.hw,
+		[CLK_BUS_UART4]		= &bus_uart4_clk.common.hw,
+		[CLK_BUS_UART5]		= &bus_uart5_clk.common.hw,
+		[CLK_BUS_UART6]		= &bus_uart6_clk.common.hw,
+		[CLK_BUS_I2C0]		= &bus_i2c0_clk.common.hw,
+		[CLK_BUS_I2C1]		= &bus_i2c1_clk.common.hw,
+		[CLK_BUS_I2C2]		= &bus_i2c2_clk.common.hw,
+		[CLK_BUS_I2C3]		= &bus_i2c3_clk.common.hw,
+		[CLK_BUS_I2C4]		= &bus_i2c4_clk.common.hw,
+		[CLK_BUS_I2C5]		= &bus_i2c5_clk.common.hw,
+		[CLK_BUS_I2C6]		= &bus_i2c6_clk.common.hw,
+		[CLK_BUS_I2C7]		= &bus_i2c7_clk.common.hw,
+		[CLK_BUS_I2C8]		= &bus_i2c8_clk.common.hw,
+		[CLK_BUS_I2C9]		= &bus_i2c9_clk.common.hw,
+		[CLK_BUS_I2C10]		= &bus_i2c10_clk.common.hw,
+		[CLK_BUS_I2C11]		= &bus_i2c11_clk.common.hw,
+		[CLK_BUS_I2C12]		= &bus_i2c12_clk.common.hw,
 		[CLK_SPI0]		= &spi0_clk.common.hw,
+		[CLK_BUS_SPI0]		= &bus_spi0_clk.common.hw,
 		[CLK_SPI1]		= &spi1_clk.common.hw,
+		[CLK_BUS_SPI1]		= &bus_spi1_clk.common.hw,
 		[CLK_SPI2]		= &spi2_clk.common.hw,
+		[CLK_BUS_SPI2]		= &bus_spi2_clk.common.hw,
 		[CLK_SPIF]		= &spif_clk.common.hw,
+		[CLK_BUS_SPIF]		= &bus_spif_clk.common.hw,
 		[CLK_SPI3]		= &spi3_clk.common.hw,
+		[CLK_BUS_SPI3]		= &bus_spi3_clk.common.hw,
 		[CLK_SPI4]		= &spi4_clk.common.hw,
+		[CLK_BUS_SPI4]		= &bus_spi4_clk.common.hw,
 		[CLK_GPADC0_24M]	= &gpadc0_24m_clk.common.hw,
+		[CLK_BUS_GPADC0]	= &bus_gpadc0_clk.common.hw,
+		[CLK_BUS_THS0]		= &bus_ths0_clk.common.hw,
 		[CLK_IRRX]		= &irrx_clk.common.hw,
+		[CLK_BUS_IRRX]		= &bus_irrx_clk.common.hw,
 		[CLK_IRTX]		= &irtx_clk.common.hw,
+		[CLK_BUS_IRTX]		= &bus_irtx_clk.common.hw,
+		[CLK_BUS_LRADC]		= &bus_lradc_clk.common.hw,
 		[CLK_SGPIO]		= &sgpio_clk.common.hw,
+		[CLK_BUS_SGPIO]		= &bus_sgpio_clk.common.hw,
 		[CLK_LPC]		= &lpc_clk.common.hw,
+		[CLK_BUS_LPC]		= &bus_lpc_clk.common.hw,
 		[CLK_I2SPCM0]		= &i2spcm0_clk.common.hw,
+		[CLK_BUS_I2SPCM0]	= &bus_i2spcm0_clk.common.hw,
 		[CLK_I2SPCM1]		= &i2spcm1_clk.common.hw,
+		[CLK_BUS_I2SPCM1]	= &bus_i2spcm1_clk.common.hw,
 		[CLK_I2SPCM2]		= &i2spcm2_clk.common.hw,
 		[CLK_I2SPCM2_ASRC]	= &i2spcm2_asrc_clk.common.hw,
+		[CLK_BUS_I2SPCM2]	= &bus_i2spcm2_clk.common.hw,
 		[CLK_I2SPCM3]		= &i2spcm3_clk.common.hw,
+		[CLK_BUS_I2SPCM3]	= &bus_i2spcm3_clk.common.hw,
 		[CLK_I2SPCM4]		= &i2spcm4_clk.common.hw,
+		[CLK_BUS_I2SPCM4]	= &bus_i2spcm4_clk.common.hw,
 		[CLK_SPDIF_TX]		= &spdif_tx_clk.common.hw,
 		[CLK_SPDIF_RX]		= &spdif_rx_clk.common.hw,
+		[CLK_BUS_SPDIF]		= &bus_spdif_clk.common.hw,
 		[CLK_DMIC]		= &dmic_clk.common.hw,
+		[CLK_BUS_DMIC]		= &bus_dmic_clk.common.hw,
 		[CLK_USB_OHCI0]		= &usb_ohci0_clk.common.hw,
+		[CLK_BUS_OHCI0]		= &bus_ohci0_clk.common.hw,
+		[CLK_BUS_EHCI0]		= &bus_ehci0_clk.common.hw,
+		[CLK_BUS_OTG]		= &bus_otg_clk.common.hw,
 		[CLK_USB_OHCI1]		= &usb_ohci1_clk.common.hw,
+		[CLK_BUS_OHCI1]		= &bus_ohci1_clk.common.hw,
+		[CLK_BUS_EHCI1]		= &bus_ehci1_clk.common.hw,
 		[CLK_USB01_REF]		= &usb01_ref_clk.common.hw,
 		[CLK_USB2_U2_REF]	= &usb2_u2_ref_clk.common.hw,
 		[CLK_USB2_SUSPEND]	= &usb2_suspend_clk.common.hw,
@@ -1677,25 +2160,41 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 		[CLK_SERDES_PHY]	= &serdes_phy_clk.common.hw,
 		[CLK_GMAC_PTP]		= &gmac_ptp_clk.common.hw,
 		[CLK_GMAC0_PHY]		= &gmac0_phy_clk.common.hw,
+		[CLK_BUS_GMAC0]		= &bus_gmac0_clk.common.hw,
 		[CLK_GMAC1_PHY]		= &gmac1_phy_clk.common.hw,
+		[CLK_BUS_GMAC1]		= &bus_gmac1_clk.common.hw,
 		[CLK_TCON_LCD0]		= &tcon_lcd0_clk.common.hw,
+		[CLK_BUS_TCON_LCD0]	= &bus_tcon_lcd0_clk.common.hw,
 		[CLK_TCON_LCD1]		= &tcon_lcd1_clk.common.hw,
+		[CLK_BUS_TCON_LCD1]	= &bus_tcon_lcd1_clk.common.hw,
 		[CLK_TCON_LCD2]		= &tcon_lcd2_clk.common.hw,
+		[CLK_BUS_TCON_LCD2]	= &bus_tcon_lcd2_clk.common.hw,
 		[CLK_DSI0]		= &dsi0_clk.common.hw,
+		[CLK_BUS_DSI0]		= &bus_dsi0_clk.common.hw,
 		[CLK_DSI1]		= &dsi1_clk.common.hw,
+		[CLK_BUS_DSI1]		= &bus_dsi1_clk.common.hw,
 		[CLK_COMBPHY0]		= &combphy0_clk.common.hw,
 		[CLK_COMBPHY1]		= &combphy1_clk.common.hw,
+		[CLK_BUS_TCON_TV0]	= &bus_tcon_tv0_clk.common.hw,
+		[CLK_BUS_TCON_TV1]	= &bus_tcon_tv1_clk.common.hw,
 		[CLK_EDP_TV]		= &edp_tv_clk.common.hw,
+		[CLK_BUS_EDP_TV]	= &bus_edp_tv_clk.common.hw,
 		[CLK_HDMI_CEC_32K]	= &hdmi_cec_32k_clk.common.hw,
 		[CLK_HDMI_CEC]		= &hdmi_cec_clk.common.hw,
 		[CLK_HDMI_TV]		= &hdmi_tv_clk.common.hw,
+		[CLK_BUS_HDMI_TV]	= &bus_hdmi_tv_clk.common.hw,
 		[CLK_HDMI_SFR]		= &hdmi_sfr_clk.common.hw,
 		[CLK_HDCP_ESM]		= &hdcp_esm_clk.common.hw,
+		[CLK_BUS_DPSS_TOP0]	= &bus_dpss_top0_clk.common.hw,
+		[CLK_BUS_DPSS_TOP1]	= &bus_dpss_top1_clk.common.hw,
 		[CLK_LEDC]		= &ledc_clk.common.hw,
+		[CLK_BUS_LEDC]		= &bus_ledc_clk.common.hw,
+		[CLK_BUS_DSC]		= &bus_dsc_clk.common.hw,
 		[CLK_CSI_MASTER0]	= &csi_master0_clk.common.hw,
 		[CLK_CSI_MASTER1]	= &csi_master1_clk.common.hw,
 		[CLK_CSI_MASTER2]	= &csi_master2_clk.common.hw,
 		[CLK_CSI]		= &csi_clk.common.hw,
+		[CLK_BUS_CSI]		= &bus_csi_clk.common.hw,
 		[CLK_ISP]		= &isp_clk.common.hw,
 		[CLK_RES_DCAP_24M]	= &res_dcap_24m_clk.common.hw,
 		[CLK_APB2JTAG]		= &apb2jtag_clk.common.hw,
Signature · 1 line
2.55.0
#20 lore raw

Re: [PATCH v6 7/8] clk: sunxi-ng: a733: Add bus clock gates

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] clk: sunxi-ng: ahb_store_clk is missing CLK_IS_CRITICAL flag --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] clk: sunxi-ng: ahb_store_clk is missing CLK_IS_CRITICAL flag
--

commit f3ca9c131f39f726826090f6af6752e7b39c004c
Author: Junhui Liu <[email protected]>

clk: sunxi-ng: a733: Add bus clock gates

This commit adds bus clock gates that control access to the device register interfaces on the Allwinner A733 SoC. It also intends to mark the ahb-store, mbus-store, and ahb-cpus clocks as critical to prevent access breakage to boot and storage devices.

Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +0 -0

[ ... ]

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 571

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+static SUNXI_CCU_GATE_HWS(ahb_msi_lite0_clk, "ahb-msi-lite0", ahb_hws,
+			  0x5c0, BIT(16), 0);
+
+/* This gate controls access to the storage controller MMIO registers. */
+static SUNXI_CCU_GATE_HWS(ahb_store_clk, "ahb-store", ahb_hws,
+			  0x5c0, BIT(24), 0);

[Severity: High]
The commit message notes that the ahb-store clock should be marked as critical, but the definition of ahb_store_clk here uses 0 for its flags parameter instead of CLK_IS_CRITICAL.

During late boot, the Common Clock Framework automatically disables any clocks that have no active consumers holding a reference to them.

Could this omission allow the framework to inadvertently gate the storage controller MMIO registers, leading to a system freeze or storage probe failures?

Quoted 5 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+static const struct clk_hw *ahb_store_hws[] = { &ahb_store_clk.common.hw };
+
+/* Keep enabled for access to the CPUS domain registers. */
+static SUNXI_CCU_GATE_HWS(ahb_cpus_clk, "ahb-cpus", ahb_hws,
+			  0x5c0, BIT(28), CLK_IS_CRITICAL);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
author
#21 lore raw

Re: [PATCH v6 7/8] clk: sunxi-ng: a733: Add bus clock gates

Quoted 20 lines · sashiko-bot

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] clk: sunxi-ng: ahb_store_clk is missing CLK_IS_CRITICAL flag
--

commit f3ca9c131f39f726826090f6af6752e7b39c004c
Author: Junhui Liu <[email protected]>

clk: sunxi-ng: a733: Add bus clock gates

This commit adds bus clock gates that control access to the device register interfaces on the Allwinner A733 SoC. It also intends to mark the ahb-store, mbus-store, and ahb-cpus clocks as critical to prevent access breakage to boot and storage devices.

Quoted 3 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +0 -0

[ ... ]

Quoted 11 lines

drivers/clk/sunxi-ng/ccu-sun60i-a733.c static SUNXI_CCU_M_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0x588 · line 571

Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +6 -0
+static SUNXI_CCU_GATE_HWS(ahb_msi_lite0_clk, "ahb-msi-lite0", ahb_hws,
+			  0x5c0, BIT(16), 0);
+
+/* This gate controls access to the storage controller MMIO registers. */
+static SUNXI_CCU_GATE_HWS(ahb_store_clk, "ahb-store", ahb_hws,
+			  0x5c0, BIT(24), 0);

[Severity: High]
The commit message notes that the ahb-store clock should be marked as critical, but the definition of ahb_store_clk here uses 0 for its flags parameter instead of CLK_IS_CRITICAL.

Oops, I forgot to update the commit message accordingly. I will send a new version to update it.

Quoted 7 lines

During late boot, the Common Clock Framework automatically disables any clocks that have no active consumers holding a reference to them.

Could this omission allow the framework to inadvertently gate the storage controller MMIO registers, leading to a system freeze or storage probe failures?

ahb_store_clk has already been set as the parent of the NAND, MMC, SPI, SPIF and UFS bus gates. Therefore, when any storage-related peripheral is in use, ahb_store_clk will be enabled through the clock dependency, so it no longer needs the CLK_IS_CRITICAL flag.

Quoted 6 lines
Quoted 6 lines
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +5 -0
+static const struct clk_hw *ahb_store_hws[] = { &ahb_store_clk.common.hw };
+
+/* Keep enabled for access to the CPUS domain registers. */
+static SUNXI_CCU_GATE_HWS(ahb_cpus_clk, "ahb-cpus", ahb_hws,
+			  0x5c0, BIT(28), CLK_IS_CRITICAL);
Signature · 2 lines
Best regards,
Junhui Liu
author
#22 lore raw

PATCH v6 8/8 clk: sunxi-ng: a733: Add reset lines

In reply to Junhui Liu

Add the reset lines for the Allwinner A733 SoC. These reset control bits are integrated into the Bus Gate Reset (BGR) registers, typically sharing the same register address with their corresponding bus clock gates. Integrate them into the main CCU driver using the existing sunxi-ng ccu_reset framework, allowing the CCU to also function as a reset controller for the SoC.

---
 drivers/clk/sunxi-ng/ccu-sun60i-a733.c | 126 +++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)
drivers/clk/sunxi-ng/ccu-sun60i-a733.c +126 -0
index c26b640fd257..cc2b229e2e6a 100644
@@ -26,6 +26,7 @@
 #include <dt-bindings/reset/allwinner,sun60i-a733-ccu.h>
 
 #include "ccu_common.h"
+#include "ccu_reset.h"
 
 #include "ccu_div.h"
 #include "ccu_gate.h"
@@ -2212,11 +2213,136 @@ static struct clk_hw_onecell_data sun60i_a733_hw_clks = {
 	.num	= CLK_FANOUT3 + 1,
 };
 
+static const struct ccu_reset_map sun60i_a733_ccu_resets[] = {
+	[RST_BUS_ITS_PCIE0]		= { 0x574, BIT(16) },
+	[RST_BUS_IOMMU0_SYS]		= { 0x58c, BIT(16) },
+	[RST_BUS_MSI_LITE0_AHB]		= { 0x594, BIT(16) },
+	[RST_BUS_MSI_LITE0_MBUS]	= { 0x594, BIT(17) },
+	[RST_BUS_MSI_LITE1_AHB]		= { 0x59c, BIT(16) },
+	[RST_BUS_MSI_LITE1_MBUS]	= { 0x59c, BIT(17) },
+	[RST_BUS_MSI_LITE2_AHB]		= { 0x5a4, BIT(16) },
+	[RST_BUS_MSI_LITE2_MBUS]	= { 0x5a4, BIT(17) },
+	[RST_BUS_IOMMU1_SYS]		= { 0x5b4, BIT(16) },
+	[RST_BUS_DMA0]			= { 0x704, BIT(16) },
+	[RST_BUS_DMA1]			= { 0x70c, BIT(16) },
+	[RST_BUS_SPINLOCK]		= { 0x724, BIT(16) },
+	[RST_BUS_MSGBOX]		= { 0x744, BIT(16) },
+	[RST_BUS_PWM0]			= { 0x784, BIT(16) },
+	[RST_BUS_PWM1]			= { 0x78c, BIT(16) },
+	[RST_BUS_DBG]			= { 0x7a4, BIT(16) },
+	[RST_BUS_SYSDAP]		= { 0x7ac, BIT(16) },
+	[RST_BUS_TIMER0]		= { 0x850, BIT(16) },
+	[RST_BUS_DE0]			= { 0xa04, BIT(16) },
+	[RST_BUS_DI]			= { 0xa24, BIT(16) },
+	[RST_BUS_G2D]			= { 0xa44, BIT(16) },
+	[RST_BUS_EINK]			= { 0xa6c, BIT(16) },
+	[RST_BUS_DE_SYS]		= { 0xa74, BIT(16) },
+	[RST_BUS_VE_ENC0]		= { 0xa8c, BIT(16) },
+	[RST_BUS_VE_DEC0]		= { 0xa8c, BIT(18) },
+	[RST_BUS_CE]			= { 0xac4, BIT(16) },
+	[RST_BUS_CE_SYS]		= { 0xac4, BIT(17) },
+	[RST_BUS_NPU_CORE]		= { 0xb04, BIT(16) },
+	[RST_BUS_NPU_AXI]		= { 0xb04, BIT(17) },
+	[RST_BUS_NPU_AHB]		= { 0xb04, BIT(18) },
+	[RST_BUS_NPU_SRAM]		= { 0xb04, BIT(19) },
+	[RST_BUS_GPU0]			= { 0xb24, BIT(16) },
+	[RST_BUS_DRAM0]			= { 0xc0c, BIT(16) },
+	[RST_BUS_NAND0]			= { 0xc8c, BIT(16) },
+	[RST_BUS_MMC0]			= { 0xd0c, BIT(16) },
+	[RST_BUS_MMC1]			= { 0xd1c, BIT(16) },
+	[RST_BUS_MMC2]			= { 0xd2c, BIT(16) },
+	[RST_BUS_MMC3]			= { 0xd3c, BIT(16) },
+	[RST_BUS_UFS_AHB]		= { 0xd8c, BIT(16) },
+	[RST_BUS_UFS_AXI]		= { 0xd8c, BIT(17) },
+	[RST_BUS_UFS_PHY]		= { 0xd8c, BIT(18) },
+	[RST_BUS_UFS_CORE]		= { 0xd8c, BIT(19) },
+	[RST_BUS_UART0]			= { 0xe00, BIT(16) },
+	[RST_BUS_UART1]			= { 0xe04, BIT(16) },
+	[RST_BUS_UART2]			= { 0xe08, BIT(16) },
+	[RST_BUS_UART3]			= { 0xe0c, BIT(16) },
+	[RST_BUS_UART4]			= { 0xe10, BIT(16) },
+	[RST_BUS_UART5]			= { 0xe14, BIT(16) },
+	[RST_BUS_UART6]			= { 0xe18, BIT(16) },
+	[RST_BUS_I2C0]			= { 0xe80, BIT(16) },
+	[RST_BUS_I2C1]			= { 0xe84, BIT(16) },
+	[RST_BUS_I2C2]			= { 0xe88, BIT(16) },
+	[RST_BUS_I2C3]			= { 0xe8c, BIT(16) },
+	[RST_BUS_I2C4]			= { 0xe90, BIT(16) },
+	[RST_BUS_I2C5]			= { 0xe94, BIT(16) },
+	[RST_BUS_I2C6]			= { 0xe98, BIT(16) },
+	[RST_BUS_I2C7]			= { 0xe9c, BIT(16) },
+	[RST_BUS_I2C8]			= { 0xea0, BIT(16) },
+	[RST_BUS_I2C9]			= { 0xea4, BIT(16) },
+	[RST_BUS_I2C10]			= { 0xea8, BIT(16) },
+	[RST_BUS_I2C11]			= { 0xeac, BIT(16) },
+	[RST_BUS_I2C12]			= { 0xeb0, BIT(16) },
+	[RST_BUS_SPI0]			= { 0xf04, BIT(16) },
+	[RST_BUS_SPI1]			= { 0xf0c, BIT(16) },
+	[RST_BUS_SPI2]			= { 0xf14, BIT(16) },
+	[RST_BUS_SPIF]			= { 0xf1c, BIT(16) },
+	[RST_BUS_SPI3]			= { 0xf24, BIT(16) },
+	[RST_BUS_SPI4]			= { 0xf2c, BIT(16) }, /* From the vendor kernel. */
+	[RST_BUS_GPADC0]		= { 0xfc4, BIT(16) },
+	[RST_BUS_THS0]			= { 0xfe4, BIT(16) },
+	[RST_BUS_IRRX]			= { 0x1004, BIT(16) },
+	[RST_BUS_IRTX]			= { 0x100c, BIT(16) },
+	[RST_BUS_LRADC]			= { 0x1024, BIT(16) },
+	[RST_BUS_SGPIO]			= { 0x1064, BIT(16) }, /* From the vendor kernel. */
+	[RST_BUS_LPC]			= { 0x1084, BIT(16) }, /* From the vendor kernel. */
+	[RST_BUS_I2SPCM0]		= { 0x120c, BIT(16) },
+	[RST_BUS_I2SPCM1]		= { 0x121c, BIT(16) },
+	[RST_BUS_I2SPCM2]		= { 0x122c, BIT(16) },
+	[RST_BUS_I2SPCM3]		= { 0x123c, BIT(16) },
+	[RST_BUS_I2SPCM4]		= { 0x124c, BIT(16) },
+	[RST_BUS_SPDIF]			= { 0x128c, BIT(16) },
+	[RST_BUS_DMIC]			= { 0x12cc, BIT(16) },
+	[RST_USB_PHY0]			= { 0x1300, BIT(30) },
+	[RST_BUS_OHCI0]			= { 0x1304, BIT(16) },
+	[RST_BUS_EHCI0]			= { 0x1304, BIT(20) },
+	[RST_BUS_OTG]			= { 0x1304, BIT(24) },
+	[RST_USB_PHY1]			= { 0x1308, BIT(30) },
+	[RST_BUS_OHCI1]			= { 0x130c, BIT(16) },
+	[RST_BUS_EHCI1]			= { 0x130c, BIT(20) },
+	[RST_BUS_USB2]			= { 0x135c, BIT(16) },
+	[RST_BUS_PCIE_PWRUP]		= { 0x138c, BIT(16) },
+	[RST_BUS_PCIE]			= { 0x138c, BIT(17) },
+	[RST_BUS_SERDES]		= { 0x13c4, BIT(16) },
+	[RST_BUS_GMAC0]			= { 0x141c, BIT(16) },
+	[RST_BUS_GMAC0_AXI]		= { 0x141c, BIT(17) },
+	[RST_BUS_GMAC1]			= { 0x142c, BIT(16) }, /* From the vendor kernel. */
+	[RST_BUS_GMAC1_AXI]		= { 0x142c, BIT(17) }, /* From the vendor kernel. */
+	[RST_BUS_TCON_LCD0]		= { 0x1504, BIT(16) },
+	[RST_BUS_TCON_LCD1]		= { 0x150c, BIT(16) },
+	[RST_BUS_TCON_LCD2]		= { 0x1514, BIT(16) }, /* From the vendor kernel. */
+	[RST_BUS_LVDS0]			= { 0x1544, BIT(16) },
+	[RST_BUS_LVDS1]			= { 0x154c, BIT(16) },
+	[RST_BUS_DSI0]			= { 0x1584, BIT(16) },
+	[RST_BUS_DSI1]			= { 0x158c, BIT(16) },
+	[RST_BUS_TCON_TV0]		= { 0x1604, BIT(16) },
+	[RST_BUS_TCON_TV1]		= { 0x160c, BIT(16) },
+	[RST_BUS_EDP]			= { 0x164c, BIT(16) },
+	[RST_BUS_HDMI_MAIN]		= { 0x168c, BIT(16) },
+	[RST_BUS_HDMI_SUB]		= { 0x168c, BIT(17) },
+	[RST_BUS_HDMI_HDCP]		= { 0x168c, BIT(18) },
+	[RST_BUS_DPSS_TOP0]		= { 0x16c4, BIT(16) },
+	[RST_BUS_DPSS_TOP1]		= { 0x16cc, BIT(16) },
+	[RST_BUS_VIDEO_OUT0]		= { 0x16e4, BIT(16) },
+	[RST_BUS_VIDEO_OUT1]		= { 0x16ec, BIT(16) },
+	[RST_BUS_LEDC]			= { 0x1704, BIT(16) },
+	[RST_BUS_DSC]			= { 0x1744, BIT(16) },
+	[RST_BUS_CSI]			= { 0x1844, BIT(16) },
+	[RST_BUS_VIDEO_IN]		= { 0x1884, BIT(16) },
+	[RST_BUS_APB2JTAG]		= { 0x1c04, BIT(16) },
+};
+
 static const struct sunxi_ccu_desc sun60i_a733_ccu_desc = {
 	.ccu_clks	= sun60i_a733_ccu_clks,
 	.num_ccu_clks	= ARRAY_SIZE(sun60i_a733_ccu_clks),
 
 	.hw_clks	= &sun60i_a733_hw_clks,
+
+	.resets		= sun60i_a733_ccu_resets,
+	.num_resets	= ARRAY_SIZE(sun60i_a733_ccu_resets),
 };
 
 static const u32 pll_regs[] = {
Signature · 1 line
2.55.0
Tested-by on the v6 series
#23 lore raw
In reply to Junhui Liu

Hi Junhui,

I tested v6 on a Radxa Cubie A7Z (A733, 1 GiB LPDDR4), Linux 7.3-rc6 with the eight patches as posted. On top of that I have Andre's pinctrl, Enzo's DT work and my local DT/UART/pinctrl changes. TF-A and U-Boot are built from source, with local changes; boot0 and SCP are still the vendor ones.

It cold boots from microSD to systemd with 8 CPUs, with the unused-clock cleanup active and no clk_ignore_unused.

About ahb-store without CLK_IS_CRITICAL: clk_summary showed mmc0, bus-mmc0 and ahb-store disabled at idle, enabled during O_DIRECT reads, and disabled again afterwards, over three cycles. The hashes matched, and there were no MMC or clock errors in the logs. mbus-store stayed on.

A native PSCI reboot also worked without the local critical flags on bus-r-riscv and bus-r-msgbox, and the data was intact afterwards.

These tests cover boot, MMC and reboot on this board, not all clocks, resets or secure boot.

Thanks,
Vinicius

#24 lore raw

Hi Junhui, Vinicius,

I can add a scoped result from a 4 GiB Cubie A7S using the vendor boot chain. With v6 unchanged, unused-clock cleanup enabled and no clk_ignore_unused, all eight CPUs reach a RAM-root console.

Ten cycles of 15 seconds idle followed by a 64 MiB O_DIRECT read show mmc0, bus-mmc0 and ahb-store disabled while idle and enabled during the read. Two additional 4 MiB direct reads at each offset give matching hashes. Card-write counters stay zero. GIC remains enabled at a reported 480 MHz; MMC operates at 50 MHz, 4-bit, 3.3 V. The board returns to vendor Linux after the test. This agrees with the parent-gate behavior Vinicius reported, on a different board and boot chain.

Correction to my earlier storage description: this is microSD on SDMMC0, not eMMC. The eMMC footprint on this A7S test unit is unpopulated; this result says nothing about eMMC on A7A/A7Z variants.

The test kernel is v7.3-rc1 plus the public dependencies and local pinctrl/MMC prerequisites: IRQ-bank allocation, firmware bias preservation, a read-only PF supply provider, MMC error handling and two DT pinctrl retry/parser fixes. ITS is disabled in the board DT because enabling it still stalls early initialization with this vendor boot chain. The GIC clock is already marked critical in v6 and remained enabled throughout these tests. I did not add critical flags to the storage clocks.

A further eight-CPU run read the full 119850 MiB card with O_DIRECT to EOF, with zero card-write counters, and returned to vendor Linux. This is a microSD/boot test report, not whole-CCU qualification. I have not validated LPIs, voltage switching, native PSCI reboot, suspend or other CCU consumers.

Thanks,
Enzo

Assisted-by Codex:gpt-6