Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support
@ 2026-08-06  9:25 evon.chiam
  2026-08-06  9:25 ` [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix evon.chiam
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

This series adds Clock Manager support for the Altera SoCFPGA Agilex72
platform. It also moves the Agilex72 device trees under dts/altera and
switches the board/SoC compatible strings to the "altr" vendor prefix,
matching Agilex7m and vendor-prefixes.yaml.

The Agilex72 clock manager exposes multiple register regions (clkmgr and
three GPPLLs) and provides the peripheral clocks used by the SoC. The
driver registers the PLL, peripheral, and gate clock tree, while the DT
describes the external input references and the clock manager node.

Patch summary:
  1/5: Fix Agilex72 compatible strings in the altera DT binding
  2/5: Add Agilex72 clock manager DT binding and clock ID header
  3/5: Add Agilex72 clock manager driver
  4/5: Move Agilex72 DT from dts/intel to dts/altera and use altr
  5/5: Add clock manager and input clocks to the Agilex72 DT

Chiam, Evon (5):
  dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix
  dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager
    binding
  clk: socfpga: agilex72: add clock manager driver for Agilex72
  arm64: dts: altera: move Agilex72 DT and use altr prefix
  arm64: dts: altera: agilex72: add clock manager support

 .../devicetree/bindings/arm/altera.yaml       |    4 +-
 .../bindings/clock/altr,agilex72-clkmgr.yaml  |   86 ++
 MAINTAINERS                                   |    5 +
 arch/arm64/boot/dts/altera/Makefile           |    3 +-
 .../{intel => altera}/socfpga_agilex72.dtsi   |   48 +-
 .../socfpga_agilex72_socdk.dts                |   14 +-
 arch/arm64/boot/dts/intel/Makefile            |    1 -
 drivers/clk/socfpga/Kconfig                   |    3 +-
 drivers/clk/socfpga/Makefile                  |    2 +-
 drivers/clk/socfpga/clk-agilex72.c            | 1181 +++++++++++++++++
 drivers/clk/socfpga/clk-agilex72.h            |   91 ++
 .../dt-bindings/clock/altr,agilex72-clkmgr.h  |  116 ++
 12 files changed, 1542 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml
 rename arch/arm64/boot/dts/{intel => altera}/socfpga_agilex72.dtsi (74%)
 rename arch/arm64/boot/dts/{intel => altera}/socfpga_agilex72_socdk.dts (63%)
 create mode 100644 drivers/clk/socfpga/clk-agilex72.c
 create mode 100644 drivers/clk/socfpga/clk-agilex72.h
 create mode 100644 include/dt-bindings/clock/altr,agilex72-clkmgr.h

-- 
2.43.7


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

* [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix
  2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
@ 2026-08-06  9:25 ` evon.chiam
  2026-08-06  9:33   ` sashiko-bot
  2026-08-06  9:25 ` [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding evon.chiam
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

Altera has separated from Intel. Update the Agilex72 SoC and board
compatible strings to use the Altera vendor prefix instead of intel.

Signed-off-by: Chiam, Evon <evon.chiam@altera.com>
---
 Documentation/devicetree/bindings/arm/altera.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/altera.yaml b/Documentation/devicetree/bindings/arm/altera.yaml
index 3030cf46fe74..2ab53cade2fe 100644
--- a/Documentation/devicetree/bindings/arm/altera.yaml
+++ b/Documentation/devicetree/bindings/arm/altera.yaml
@@ -119,8 +119,8 @@ properties:
       - description: Agilex72 boards
         items:
           - enum:
-              - intel,socfpga-agilex72-socdk
-          - const: intel,socfpga-agilex72
+              - altr,socfpga-agilex72-socdk
+          - const: altr,socfpga-agilex72
 
       - description: Agilex7m boards
         items:
-- 
2.43.7


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

* [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding
  2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
  2026-08-06  9:25 ` [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix evon.chiam
@ 2026-08-06  9:25 ` evon.chiam
  2026-08-06  9:34   ` sashiko-bot
  2026-08-06  9:25 ` [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72 evon.chiam
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

Add binding and clock ID header for Altera SoCFPGA Agilex72 clock manager.

Signed-off-by: Chiam, Evon <evon.chiam@altera.com>
---
 .../bindings/clock/altr,agilex72-clkmgr.yaml  |  86 +++++++++++++
 .../dt-bindings/clock/altr,agilex72-clkmgr.h  | 116 ++++++++++++++++++
 2 files changed, 202 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml
 create mode 100644 include/dt-bindings/clock/altr,agilex72-clkmgr.h

diff --git a/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml b/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml
new file mode 100644
index 000000000000..cb063981f019
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/altr,agilex72-clkmgr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Altera SoCFPGA Agilex72 clock manager
+
+maintainers:
+  - Chiam, Evon <evon.chiam@altera.com>
+
+description:
+  The Altera Agilex72 Clock Manager is an integrated clock controller, which
+  generates and supplies clock to all the modules.
+
+properties:
+  compatible:
+    const: altr,agilex72-clkmgr
+
+  reg:
+    items:
+      - description: Clock manager registers
+      - description: GPPLL0 registers
+      - description: GPPLL1 registers
+      - description: GPPLL2 registers
+
+  reg-names:
+    items:
+      - const: clkmgr
+      - const: gppll0
+      - const: gppll1
+      - const: gppll2
+
+  '#clock-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    /* External reference clocks supplied to the clock manager */
+    clocks {
+      cb_intosc_div2_clk: cb-intosc-div2-clk {
+        #clock-cells = <0>;
+        compatible = "fixed-clock";
+        clock-frequency = <0>;
+      };
+
+      /* cb-intosc divided by 2, then by 5 (total divide-by-10) */
+      cb_intosc_div10_clk: cb-intosc-div10-clk {
+        #clock-cells = <0>;
+        compatible = "fixed-factor-clock";
+        clocks = <&cb_intosc_div2_clk>;
+        clock-mult = <1>;
+        clock-div = <5>;
+      };
+
+      f2s_free_clk: f2s-free-clk {
+        #clock-cells = <0>;
+        compatible = "fixed-clock";
+        clock-frequency = <0>;
+      };
+
+      osc1: osc1 {
+        #clock-cells = <0>;
+        compatible = "fixed-clock";
+        clock-frequency = <0>;
+      };
+    };
+
+    clkmgr: clock-controller@915c000 {
+      compatible = "altr,agilex72-clkmgr";
+      reg = <0x915c000 0x1000>,
+            <0x915e000 0x1000>,
+            <0x915f000 0x1000>,
+            <0x9160000 0x1000>;
+      reg-names = "clkmgr", "gppll0", "gppll1", "gppll2";
+      #clock-cells = <1>;
+    };
+...
diff --git a/include/dt-bindings/clock/altr,agilex72-clkmgr.h b/include/dt-bindings/clock/altr,agilex72-clkmgr.h
new file mode 100644
index 000000000000..c2158ac75a4f
--- /dev/null
+++ b/include/dt-bindings/clock/altr,agilex72-clkmgr.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+
+#ifndef __DT_BINDINGS_ALTR_AGILEX72_CLKMGR_H
+#define __DT_BINDINGS_ALTR_AGILEX72_CLKMGR_H
+
+/* fixed rate clocks */
+#define AGILEX72_OSC1                  0
+#define AGILEX72_CB_INTOSC_DIV2_CLK    1
+#define AGILEX72_CB_INTOSC_DIV10_CLK   2
+#define AGILEX72_F2S_FREE_CLK          3
+
+/* gppll clocks */
+#define AGILEX72_GPPLL0_CLK            4
+#define AGILEX72_GPPLL1_CLK            5
+#define AGILEX72_GPPLL2_CLK            6
+#define AGILEX72_GPPLL0_C0_CLK         7
+#define AGILEX72_GPPLL0_C1_CLK         8
+#define AGILEX72_GPPLL0_C2_CLK         9
+#define AGILEX72_GPPLL0_C3_CLK         10
+#define AGILEX72_GPPLL0_C4_CLK         11
+#define AGILEX72_GPPLL0_C5_CLK         12
+#define AGILEX72_GPPLL0_C6_CLK         13
+#define AGILEX72_GPPLL1_C0_CLK         14
+#define AGILEX72_GPPLL1_C1_CLK         15
+#define AGILEX72_GPPLL2_C0_CLK         16
+#define AGILEX72_GPPLL2_C1_CLK         17
+
+#define AGILEX72_BOOT_CLK              18
+
+/* fixed factor clocks */
+#define AGILEX72_COMP0_FREE_CLK        19
+#define AGILEX72_CORE2_FREE_CLK        20
+#define AGILEX72_CORE3_FREE_CLK        21
+#define AGILEX72_DSU_FREE_CLK          22
+#define AGILEX72_CCU_FREE_CLK          23
+#define AGILEX72_HSP_NOC_FREE_CLK      24
+#define AGILEX72_LSP_NOC_FREE_CLK      25
+#define AGILEX72_TRACE_FREE_CLK        26
+#define AGILEX72_EMAC_A_FREE_CLK       27
+#define AGILEX72_EMAC_B_FREE_CLK       28
+#define AGILEX72_EMAC_PTP_FREE_CLK     29
+#define AGILEX72_GPIO_DB_FREE_CLK      30
+#define AGILEX72_USB31_FREE_CLK        31
+#define AGILEX72_S2F_USER0_FREE_CLK    32
+#define AGILEX72_S2F_USER1_FREE_CLK    33
+#define AGILEX72_XSPI_PHY_FREE_CLK     34
+#define AGILEX72_MEMDEVICE_PHY_FREE_CLK 35
+
+/* Gate clocks */
+#define AGILEX72_COMP0_CLK             36
+#define AGILEX72_CORE2_CLK             37
+#define AGILEX72_CORE3_CLK             38
+#define AGILEX72_MPU_CLK               39
+#define AGILEX72_CCU_CLK               40
+#define AGILEX72_APU_SYS_FREE_CLK      41
+#define AGILEX72_HSP_SYS_FREE_CLK      42
+#define AGILEX72_HSP_MAIN_FREE_CLK     43
+#define AGILEX72_HSP_MAIN_CLK          44
+#define AGILEX72_HSP_MP_CLK            45
+#define AGILEX72_HSP_SP_CLK            46
+#define AGILEX72_USB2OTG_HCLK          47
+#define AGILEX72_LSP_SYS_FREE_CLK      48
+#define AGILEX72_LSP_MAIN_FREE_CLK     49
+#define AGILEX72_LSP_MAIN_CLK          50
+#define AGILEX72_LSP_MP_CLK            51
+#define AGILEX72_LSP_SP_CLK            52
+#define AGILEX72_SPIM_0_CLK            53
+#define AGILEX72_SPIM_1_CLK            54
+#define AGILEX72_SPIS_0_CLK            55
+#define AGILEX72_SPIS_1_CLK            56
+#define AGILEX72_DMA_0_CORE_CLK        57
+#define AGILEX72_DMA_0_HS_CLK          58
+#define AGILEX72_DMA_1_CORE_CLK        59
+#define AGILEX72_DMA_1_HS_CLK          60
+#define AGILEX72_I3C_0_CORE_CLK        61
+#define AGILEX72_I3C_1_CORE_CLK        62
+#define AGILEX72_I2C_0_PCLK            63
+#define AGILEX72_I2C_1_PCLK            64
+#define AGILEX72_I2C_EMAC0_PCLK        65
+#define AGILEX72_I2C_EMAC1_PCLK        66
+#define AGILEX72_I2C_EMAC2_PCLK        67
+#define AGILEX72_UART_0_PCLK           68
+#define AGILEX72_UART_1_PCLK           69
+#define AGILEX72_UART_2_PCLK           70
+#define AGILEX72_SPTIMER_0_PCLK        71
+#define AGILEX72_SPTIMER_1_PCLK        72
+#define AGILEX72_CS_AT_CLK             73
+#define AGILEX72_CS_PDBG_CLK           74
+#define AGILEX72_CS_TRACE_CLK          75
+#define AGILEX72_EMACA_DIV_CLK         76
+#define AGILEX72_EMACB_DIV_CLK         77
+#define AGILEX72_EMAC0_CLK             78
+#define AGILEX72_EMAC1_CLK             79
+#define AGILEX72_EMAC2_CLK             80
+#define AGILEX72_EMAC_PTP_CLK          81
+#define AGILEX72_GPIO_DB_CLK           82
+#define AGILEX72_USB31_SUSPEND_CLK     83
+#define AGILEX72_USB31_BUS_CLK_EARLY   84
+#define AGILEX72_S2F_USER0_CLK         85
+#define AGILEX72_S2F_USER1_CLK         86
+#define AGILEX72_XSPI_PCLK             87
+#define AGILEX72_XSPI_CLK              88
+#define AGILEX72_XSPI_PHY_CLK          89
+#define AGILEX72_SDMMC0_SDPHY_REG_CLK  90
+#define AGILEX72_SDMMC1_SDPHY_REG_CLK  91
+#define AGILEX72_SDMMC0_SDMCLK         92
+#define AGILEX72_SDMMC1_SDMCLK         93
+#define AGILEX72_SDMMC0_PHY_CLK        94
+#define AGILEX72_SDMMC1_PHY_CLK        95
+#define AGILEX72_USB31_REF_CLK         96
+#define AGILEX72_NUM_CLKS              97
+
+#endif  /* __DT_BINDINGS_ALTR_AGILEX72_CLKMGR_H */
-- 
2.43.7


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

* [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72
  2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
  2026-08-06  9:25 ` [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix evon.chiam
  2026-08-06  9:25 ` [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding evon.chiam
@ 2026-08-06  9:25 ` evon.chiam
  2026-08-06  9:38   ` sashiko-bot
  2026-08-06  9:25 ` [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix evon.chiam
  2026-08-06  9:25 ` [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support evon.chiam
  4 siblings, 1 reply; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

Add new Clock manager driver to support new Altera Agilex72 platform

Signed-off-by: Chiam, Evon <evon.chiam@altera.com>
---
 MAINTAINERS                        |    5 +
 drivers/clk/socfpga/Kconfig        |    3 +-
 drivers/clk/socfpga/Makefile       |    2 +-
 drivers/clk/socfpga/clk-agilex72.c | 1181 ++++++++++++++++++++++++++++
 drivers/clk/socfpga/clk-agilex72.h |   91 +++
 5 files changed, 1280 insertions(+), 2 deletions(-)
 create mode 100644 drivers/clk/socfpga/clk-agilex72.c
 create mode 100644 drivers/clk/socfpga/clk-agilex72.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 15011f5752a9..1b850dc3d6b6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3581,6 +3581,11 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml
 F:	drivers/media/platform/samsung/s5p-mfc/
 
+ARM/SOCFPGA AGILEX72 CLOCK DRIVER
+M:	Chiam, Evon <evon.chiam@altera.com>
+S:	Maintained
+F:	drivers/clk/socfpga/clk-agilex72.[ch]
+
 ARM/SOCFPGA ARCHITECTURE
 M:	Dinh Nguyen <dinguyen@kernel.org>
 S:	Maintained
diff --git a/drivers/clk/socfpga/Kconfig b/drivers/clk/socfpga/Kconfig
index d88277e2a898..40cac9428fbe 100644
--- a/drivers/clk/socfpga/Kconfig
+++ b/drivers/clk/socfpga/Kconfig
@@ -13,7 +13,8 @@ config CLK_INTEL_SOCFPGA32
 	default ARM && ARCH_INTEL_SOCFPGA
 
 config CLK_INTEL_SOCFPGA64
-	bool "Intel Stratix / Agilex / N5X / Agilex5 clock controller support" if COMPILE_TEST && (!ARM64 || !ARCH_INTEL_SOCFPGA)
+	bool "Intel Stratix / Agilex / N5X / Agilex5 / Agilex72 clock controller support" \
+		if COMPILE_TEST && (!ARM64 || !ARCH_INTEL_SOCFPGA)
 	default ARM64 && ARCH_INTEL_SOCFPGA
 
 endif # CLK_INTEL_SOCFPGA
diff --git a/drivers/clk/socfpga/Makefile b/drivers/clk/socfpga/Makefile
index a1ea2b988eaf..97af3dfdbbad 100644
--- a/drivers/clk/socfpga/Makefile
+++ b/drivers/clk/socfpga/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_CLK_INTEL_SOCFPGA32) += clk.o clk-gate.o clk-pll.o clk-periph.o \
 				     clk-pll-a10.o clk-periph-a10.o clk-gate-a10.o
 obj-$(CONFIG_CLK_INTEL_SOCFPGA64) += clk-s10.o \
 				     clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o \
-				     clk-agilex.o clk-agilex5.o
+				     clk-agilex.o clk-agilex5.o clk-agilex72.o
diff --git a/drivers/clk/socfpga/clk-agilex72.c b/drivers/clk/socfpga/clk-agilex72.c
new file mode 100644
index 000000000000..e350d8a9bb4d
--- /dev/null
+++ b/drivers/clk/socfpga/clk-agilex72.c
@@ -0,0 +1,1181 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <dt-bindings/clock/altr,agilex72-clkmgr.h>
+#include "clk-agilex72.h"
+
+#define EMAC_BYPASS_OFFSET          0x10
+#define CLK_MGR_FREE_SHIFT          16
+#define CLK_MGR_FREE_MASK           0x7
+#define PERI_CLK_CNT_DIV_WIDTH      11
+#define BOOTCLKSRC_MASK             0x2000000
+#define BOOTCLKSRC_SHIFT            25
+#define SOCFPGA_PLL_POWER           0
+#define BOOT_CLK                    "boot_clk"
+#define CLK_MGR_PLL_CLK_SRC_SHIFT   27
+#define CLK_MGR_PLL_CLK_SRC_MASK    0x3
+#define PLL_RATE_REG_OFFSET         0x4
+#define PLL_CR_N_HI_MASK            0xFF
+#define PLL_CR_N_LO_MASK            0x1FE00
+#define PLL_CR_N_LO_SHIFT           9
+#define PLL_CRHI_M_MASK             0x1FF00000
+#define PLL_CRHI_M_SHIFT            20
+#define PLL_CR_C_MASK               0xFF
+#define PLL_CR_BYPASS_DIV_MASK      0x100
+#define PLL_FRACT_DIV_REG_OFFSET    0x5c
+#define PLL_CR_FRACT_DIV_MASK       0xFFFFFF
+
+static bool agilex72_gate_is_emac(const char *name);
+static u8 agilex72_parent_index(const char * const *parents,
+				size_t num_parents, const char *parent_name);
+static unsigned long agilex72_boot_clk_recalc_rate(struct clk_hw *hwclk,
+						   unsigned long parent_rate);
+static unsigned long agilex72_clk_pll_recalc_rate(struct clk_hw *hwclk,
+						  unsigned long parent_rate);
+static unsigned long agilex72_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
+						     unsigned long parent_rate);
+static unsigned long
+agilex72_clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
+				      unsigned long parent_rate);
+static unsigned long agilex72_gate_clk_recalc_rate(struct clk_hw *hwclk,
+						   unsigned long parent_rate);
+static u8 agilex72_boot_get_parent(struct clk_hw *hwclk);
+static u8 agilex72_clk_pll_get_parent(struct clk_hw *hwclk);
+static u8 agilex72_peri_c_clk_get_parent(struct clk_hw *hwclk);
+static u8 agilex72_clk_periclk_get_parent(struct clk_hw *hwclk);
+static u8 agilex72_gate_get_parent(struct clk_hw *hwclk);
+
+/* External parent clocks come from DT via fw_name */
+static const char * const boot_pll_parents[] = {
+	"osc1",
+	"cb-intosc-div2-clk",
+};
+
+static const char * const gppll0_clk_parents[] = {
+	"osc1",
+	"cb-intosc-div10-clk",
+	"f2s-free-clk",
+};
+
+static const char * const gppll1_clk_parents[] = {
+	"osc1",
+	"cb-intosc-div10-clk",
+	"f2s-free-clk",
+};
+
+static const char * const gppll2_clk_parents[] = {
+	"osc1",
+	"cb-intosc-div10-clk",
+	"f2s-free-clk",
+};
+
+/* Core free muxes */
+static const char * const comp0_free_mux[] = {
+	"gppll1-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const core2_free_mux[] = {
+	"gppll2-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const core3_free_mux[] = {
+	"gppll2-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const dsu_free_mux[] = {
+	"gppll1-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const ccu_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const hsp_noc_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const lsp_noc_free_mux[] = {
+	"gppll0-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const trace_free_mux[] = {
+	"gppll0-c2",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const emaca_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const emacb_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const emac_ptp_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const gpio_db_free_mux[] = {
+	"gppll0-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const usb31_free_mux[] = {
+	"gppll0-c0",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const s2f_user0_free_mux[] = {
+	"gppll0-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const s2f_user1_free_mux[] = {
+	"gppll0-c1",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const xspi_phy_clk_mux[] = {
+	"gppll0-c3",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+static const char * const memdevice_phy_clk_mux[] = {
+	"gppll0-c3",
+	"osc1",
+	"cb-intosc-div2-clk",
+	"f2s-free-clk",
+};
+
+/* Secondary muxes between free_clk and boot_clk */
+static const char * const comp0_mux[] = {
+	"comp0_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const core2_mux[] = {
+	"core2_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const core3_mux[] = {
+	"core3_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const mpu_mux[] = {
+	"dsu_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const ccu_mux[] = {
+	"ccu_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const hsp_noc_mux[] = {
+	"hsp_noc_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const lsp_noc_mux[] = {
+	"lsp_noc_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const cs_at_mux[] = {
+	"lsp_noc_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const cs_pdbg_mux[] = {
+	"lsp_noc_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const cs_trace_mux[] = {
+	"trace_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const emac_mux[] = {
+	"emaca_div_clk",
+	"emacb_div_clk",
+	BOOT_CLK,
+};
+
+static const char * const emac_ptp_mux[] = {
+	"emac_ptp_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const gpio_db_mux[] = {
+	"gpio_db_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const usb31_mux[] = {
+	"usb31_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const s2f_user0_mux[] = {
+	"s2f_user0_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const s2f_user1_mux[] = {
+	"s2f_user1_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const xspi_mux[] = {
+	"xspi_phy_free_clk",
+	BOOT_CLK,
+};
+
+static const char * const memdevice_phy_mux[] = {
+	"memdevice_phy_free_clk",
+	BOOT_CLK,
+};
+
+static const struct agilex72_pll_clock pll_clks[] = {
+	{
+		.id = AGILEX72_BOOT_CLK,
+		.name = BOOT_CLK,
+		.parent_names = boot_pll_parents,
+		.num_parents = ARRAY_SIZE(boot_pll_parents),
+		.offset = 0x4,
+	},
+	{
+		.id = AGILEX72_GPPLL0_CLK,
+		.name = "gppll0",
+		.parent_names = gppll0_clk_parents,
+		.num_parents = ARRAY_SIZE(gppll0_clk_parents),
+		.offset = 0x160,
+	},
+	{
+		.id = AGILEX72_GPPLL1_CLK,
+		.name = "gppll1",
+		.parent_names = gppll1_clk_parents,
+		.num_parents = ARRAY_SIZE(gppll1_clk_parents),
+		.offset = 0x80,
+	},
+	{
+		.id = AGILEX72_GPPLL2_CLK,
+		.name = "gppll2",
+		.parent_names = gppll2_clk_parents,
+		.num_parents = ARRAY_SIZE(gppll2_clk_parents),
+		.offset = 0x60,
+	},
+};
+
+static const struct agilex72_perip_c_clock main_perip_c_clks[] = {
+	{ AGILEX72_GPPLL0_C0_CLK,
+	  "gppll0-c0", "gppll0", 1, 0x24, 23,  0, 8, 8 },
+	{ AGILEX72_GPPLL0_C1_CLK,
+	  "gppll0-c1", "gppll0", 1, 0x28, 14, 23, 8, 8 },
+	{ AGILEX72_GPPLL0_C2_CLK,
+	  "gppll0-c2", "gppll0", 1, 0x2c,  0,  9, 8, 8 },
+	{ AGILEX72_GPPLL0_C3_CLK,
+	  "gppll0-c3", "gppll0", 1, 0x30,  0,  9, 8, 8 },
+	{ AGILEX72_GPPLL0_C4_CLK,
+	  "gppll0-c4", "gppll0", 1, 0x38,  0,  9, 8, 8 },
+	{ AGILEX72_GPPLL0_C5_CLK,
+	  "gppll0-c5", "gppll0", 1, 0x3c,  0,  9, 8, 8 },
+	{ AGILEX72_GPPLL0_C6_CLK,
+	  "gppll0-c6", "gppll0", 1, 0x40,  0,  9, 8, 8 },
+	{ AGILEX72_GPPLL1_C0_CLK,
+	  "gppll1-c0", "gppll1", 1, 0x24, 23,  0, 8, 8 },
+	{ AGILEX72_GPPLL1_C1_CLK,
+	  "gppll1-c1", "gppll1", 1, 0x28, 14, 23, 8, 8 },
+	{ AGILEX72_GPPLL2_C0_CLK,
+	  "gppll2-c0", "gppll2", 1, 0x24, 23,  0, 8, 8 },
+	{ AGILEX72_GPPLL2_C1_CLK,
+	  "gppll2-c1", "gppll2", 1, 0x28, 14, 23, 8, 8 },
+};
+
+/* Non-SW clock-gated enabled clocks */
+static const struct agilex72_perip_cnt_clock main_perip_cnt_clks[] = {
+	{ AGILEX72_COMP0_FREE_CLK, "comp0_free_clk",
+	  comp0_free_mux, ARRAY_SIZE(comp0_free_mux), 0xbc },
+	{ AGILEX72_CORE2_FREE_CLK, "core2_free_clk",
+	  core2_free_mux, ARRAY_SIZE(core2_free_mux), 0xb8 },
+	{ AGILEX72_CORE3_FREE_CLK, "core3_free_clk",
+	  core3_free_mux, ARRAY_SIZE(core3_free_mux), 0xb4 },
+	{ AGILEX72_DSU_FREE_CLK, "dsu_free_clk",
+	  dsu_free_mux, ARRAY_SIZE(dsu_free_mux), 0xc0 },
+	{ AGILEX72_CCU_FREE_CLK, "ccu_free_clk",
+	  ccu_free_mux, ARRAY_SIZE(ccu_free_mux), 0xc4 },
+	{ AGILEX72_HSP_NOC_FREE_CLK, "hsp_noc_free_clk",
+	  hsp_noc_free_mux, ARRAY_SIZE(hsp_noc_free_mux), 0x104 },
+	{ AGILEX72_LSP_NOC_FREE_CLK, "lsp_noc_free_clk",
+	  lsp_noc_free_mux, ARRAY_SIZE(lsp_noc_free_mux), 0x108 },
+	{ AGILEX72_TRACE_FREE_CLK, "trace_free_clk",
+	  trace_free_mux, ARRAY_SIZE(trace_free_mux), 0x144 },
+	{ AGILEX72_EMAC_A_FREE_CLK, "emaca_free_clk",
+	  emaca_free_mux, ARRAY_SIZE(emaca_free_mux), 0x128 },
+	{ AGILEX72_EMAC_B_FREE_CLK, "emacb_free_clk",
+	  emacb_free_mux, ARRAY_SIZE(emacb_free_mux), 0x12c },
+	{ AGILEX72_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk",
+	  emac_ptp_free_mux, ARRAY_SIZE(emac_ptp_free_mux), 0x130 },
+	{ AGILEX72_GPIO_DB_FREE_CLK, "gpio_db_free_clk",
+	  gpio_db_free_mux, ARRAY_SIZE(gpio_db_free_mux), 0x134 },
+	{ AGILEX72_USB31_FREE_CLK, "usb31_free_clk",
+	  usb31_free_mux, ARRAY_SIZE(usb31_free_mux), 0x140 },
+	{ AGILEX72_S2F_USER0_FREE_CLK, "s2f_user0_free_clk",
+	  s2f_user0_free_mux, ARRAY_SIZE(s2f_user0_free_mux), 0x138 },
+	{ AGILEX72_S2F_USER1_FREE_CLK, "s2f_user1_free_clk",
+	  s2f_user1_free_mux, ARRAY_SIZE(s2f_user1_free_mux), 0x13c },
+	{ AGILEX72_XSPI_PHY_FREE_CLK, "xspi_phy_free_clk",
+	  xspi_phy_clk_mux, ARRAY_SIZE(xspi_phy_clk_mux), 0x154 },
+	{ AGILEX72_MEMDEVICE_PHY_FREE_CLK, "memdevice_phy_free_clk",
+	  memdevice_phy_clk_mux, ARRAY_SIZE(memdevice_phy_clk_mux), 0x148 },
+};
+
+static const char * const hsp_mp_clk_parent[] = { "hsp_mp_clk" };
+static const char * const lsp_main_parent[] = { "lsp_main_clk" };
+static const char * const lsp_mp_parent[] = { "lsp_mp_clk" };
+static const char * const lsp_sp_parent[] = { "lsp_sp_clk" };
+static const char * const usb31_bus_clk_early_parents[] = { "hsp_main_clk" };
+static const char * const emaca_div_parents[] = { "emaca_free_clk" };
+static const char * const emacb_div_parents[] = { "emacb_free_clk" };
+
+/* SW Clock gate enabled clocks */
+static const struct agilex72_gate_clock gate_clks[] = {
+	{ AGILEX72_COMP0_CLK, "comp0_clk", comp0_mux,
+	  ARRAY_SIZE(comp0_mux), 0x30, 8, 0, 0, 0, 0x3c, 5, 0 },
+	{ AGILEX72_CORE2_CLK, "core2_clk", core2_mux,
+	  ARRAY_SIZE(core2_mux), 0x30, 10, 0, 0, 0, 0x3c, 10, 0 },
+	{ AGILEX72_CORE3_CLK, "core3_clk", core3_mux,
+	  ARRAY_SIZE(core3_mux), 0x30, 11, 0, 0, 0, 0x3c, 11, 0 },
+	{ AGILEX72_MPU_CLK, "mpu_clk", mpu_mux,
+	  ARRAY_SIZE(mpu_mux), 0x30, 7, 0, 0, 0, 0x3c, 4, 0 },
+	{ AGILEX72_CCU_CLK, "ccu_clk", ccu_mux,
+	  ARRAY_SIZE(ccu_mux), 0x30, 6, 0, 0, 0, 0x3c, 3, 0 },
+	{ AGILEX72_APU_SYS_FREE_CLK, "apu_sys_free_clk", ccu_mux,
+	  ARRAY_SIZE(ccu_mux), 0, 0, 0x50, 22, 2, 0x3c, 3, 0 },
+	{ AGILEX72_HSP_SYS_FREE_CLK, "hsp_sys_free_clk", hsp_noc_mux,
+	  ARRAY_SIZE(hsp_noc_mux), 0, 0, 0x10c, 8, 2, 0xf0, 9, 0 },
+	{ AGILEX72_HSP_MAIN_FREE_CLK, "hsp_main_free_clk", hsp_noc_mux,
+	  ARRAY_SIZE(hsp_noc_mux), 0, 0, 0, 0, 0, 0xf0, 9, 0 },
+	{ AGILEX72_HSP_MAIN_CLK, "hsp_main_clk", hsp_noc_mux,
+	  ARRAY_SIZE(hsp_noc_mux), 0xe0, 1, 0, 0, 0, 0xf0, 9, 0 },
+	{ AGILEX72_HSP_MP_CLK, "hsp_mp_clk", hsp_noc_mux,
+	  ARRAY_SIZE(hsp_noc_mux), 0xe0, 2, 0x10c, 10, 2, 0xf0, 9, 0 },
+	{ AGILEX72_HSP_SP_CLK, "hsp_sp_clk", hsp_noc_mux,
+	  ARRAY_SIZE(hsp_noc_mux), 0xe0, 3, 0x10c, 12, 2, 0xf0, 9, 0 },
+	{ AGILEX72_USB2OTG_HCLK, "usb2otg_hclk", hsp_mp_clk_parent,
+	  1, 0xe0, 0, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_LSP_SYS_FREE_CLK, "lsp_sys_free_clk", lsp_noc_mux,
+	  ARRAY_SIZE(lsp_noc_mux), 0, 0, 0x10c, 2, 2, 0xf0, 9, 0 },
+	{ AGILEX72_LSP_MAIN_FREE_CLK, "lsp_main_free_clk", lsp_noc_mux,
+	  ARRAY_SIZE(lsp_noc_mux), 0xe0, 0, 0, 0, 0, 0xf0, 9, 0 },
+	{ AGILEX72_LSP_MAIN_CLK, "lsp_main_clk", lsp_noc_mux,
+	  ARRAY_SIZE(lsp_noc_mux), 0xe0, 1, 0, 0, 0, 0xf0, 9, 0 },
+	{ AGILEX72_LSP_MP_CLK, "lsp_mp_clk", lsp_noc_mux,
+	  ARRAY_SIZE(lsp_noc_mux), 0xe0, 2, 0x10c, 4, 2, 0xf0, 9, 0 },
+	{ AGILEX72_LSP_SP_CLK, "lsp_sp_clk", lsp_noc_mux,
+	  ARRAY_SIZE(lsp_noc_mux), 0xe0, 3, 0x10c, 6, 2, 0xf0, 9, 0 },
+	{ AGILEX72_SPIM_0_CLK, "spim_0_clk", lsp_main_parent,
+	  1, 0xd0, 11, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SPIM_1_CLK, "spim_1_clk", lsp_main_parent,
+	  1, 0xd0, 12, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SPIS_0_CLK, "spis_0_clk", lsp_main_parent,
+	  1, 0xd0, 13, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SPIS_1_CLK, "spis_1_clk", lsp_main_parent,
+	  1, 0xd0, 14, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_DMA_0_CORE_CLK, "dma_0_core_clk", lsp_main_parent,
+	  1, 0xd0, 15, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_DMA_0_HS_CLK, "dma_0_hs_clk", lsp_mp_parent,
+	  1, 0xd0, 15, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_DMA_1_CORE_CLK, "dma_1_core_clk", lsp_main_parent,
+	  1, 0xd0, 16, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_DMA_1_HS_CLK, "dma_1_hs_clk", lsp_mp_parent,
+	  1, 0xd0, 16, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I3C_0_CORE_CLK, "i3c_0_core_clk", lsp_mp_parent,
+	  1, 0xd0, 22, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I3C_1_CORE_CLK, "i3c_1_core_clk", lsp_mp_parent,
+	  1, 0xd0, 23, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I2C_0_PCLK, "i2c_0_pclk", lsp_sp_parent,
+	  1, 0xd0, 17, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I2C_1_PCLK, "i2c_1_pclk", lsp_sp_parent,
+	  1, 0xd0, 18, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I2C_EMAC0_PCLK, "i2c_emac0_pclk", lsp_sp_parent,
+	  1, 0xd0, 19, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I2C_EMAC1_PCLK, "i2c_emac1_pclk", lsp_sp_parent,
+	  1, 0xd0, 20, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_I2C_EMAC2_PCLK, "i2c_emac2_pclk", lsp_sp_parent,
+	  1, 0xd0, 21, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_UART_0_PCLK, "uart_0_pclk", lsp_sp_parent,
+	  1, 0xd0, 23, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_UART_1_PCLK, "uart_1_pclk", lsp_sp_parent,
+	  1, 0xd0, 24, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_UART_2_PCLK, "uart_2_pclk", lsp_sp_parent,
+	  1, 0xd0, 25, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SPTIMER_0_PCLK, "sptimer_0_pclk", lsp_sp_parent,
+	  1, 0xd0, 29, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SPTIMER_1_PCLK, "sptimer_1_pclk", lsp_sp_parent,
+	  1, 0xd0, 30, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_CS_AT_CLK, "cs_at_clk", cs_at_mux,
+	  ARRAY_SIZE(cs_at_mux), 0xe0, 4, 0x10c, 24, 2, 0xf0, 9, 0 },
+	{ AGILEX72_CS_PDBG_CLK, "cs_pdbg_clk", cs_pdbg_mux,
+	  ARRAY_SIZE(cs_pdbg_mux), 0xe0, 4, 0x10c, 28, 2, 0xf0, 9, 0 },
+	{ AGILEX72_CS_TRACE_CLK, "cs_trace_clk", cs_trace_mux,
+	  ARRAY_SIZE(cs_trace_mux), 0xe0, 4, 0x10c, 26, 2, 0xf0, 10, 0 },
+	{ AGILEX72_EMACA_DIV_CLK, "emaca_div_clk", emaca_div_parents,
+	  1, 0, 0, 0x118, 8, 2, 0, 0, 0 },
+	{ AGILEX72_EMACB_DIV_CLK, "emacb_div_clk", emacb_div_parents,
+	  1, 0, 0, 0x118, 10, 2, 0, 0, 0 },
+	{ AGILEX72_EMAC0_CLK, "emac0_clk", emac_mux,
+	  ARRAY_SIZE(emac_mux), 0xd0, 0, 0, 0, 0, 0x100, 26, 0 },
+	{ AGILEX72_EMAC1_CLK, "emac1_clk", emac_mux,
+	  ARRAY_SIZE(emac_mux), 0xd0, 1, 0, 0, 0, 0x100, 27, 0 },
+	{ AGILEX72_EMAC2_CLK, "emac2_clk", emac_mux,
+	  ARRAY_SIZE(emac_mux), 0xd0, 2, 0, 0, 0, 0x100, 28, 0 },
+	{ AGILEX72_EMAC_PTP_CLK, "emac_ptp_clk", emac_ptp_mux,
+	  ARRAY_SIZE(emac_ptp_mux), 0xd0, 3, 0, 0, 0, 0xf0, 2, 0 },
+	{ AGILEX72_GPIO_DB_CLK, "gpio_db_clk", gpio_db_mux,
+	  ARRAY_SIZE(gpio_db_mux), 0xd0, 4, 0x114, 0, 16, 0xf0, 3, 1 },
+	{ AGILEX72_USB31_SUSPEND_CLK, "usb31_suspend_clk", usb31_mux,
+	  ARRAY_SIZE(usb31_mux), 0xe0, 7, 0x118, 12, 6, 0xf0, 7, 1 },
+	{ AGILEX72_USB31_BUS_CLK_EARLY, "usb31_bus_clk_early",
+	  usb31_bus_clk_early_parents, 1, 0xe0, 7, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_S2F_USER0_CLK, "s2f_user0_clk", s2f_user0_mux,
+	  ARRAY_SIZE(s2f_user0_mux), 0xd0, 27, 0, 0, 0, 0xf0, 4, 0 },
+	{ AGILEX72_S2F_USER1_CLK, "s2f_user1_clk", s2f_user1_mux,
+	  ARRAY_SIZE(s2f_user1_mux), 0xd0, 28, 0, 0, 0, 0xf0, 5, 0 },
+	{ AGILEX72_XSPI_PCLK, "xspi_pclk", lsp_mp_parent,
+	  1, 0xd0, 9, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_XSPI_CLK, "xspi_clk", xspi_mux,
+	  ARRAY_SIZE(xspi_mux), 0xd0, 9, 0x110, 8, 2, 0xf0, 14, 0 },
+	{ AGILEX72_XSPI_PHY_CLK, "xspi_phy_clk", xspi_mux,
+	  ARRAY_SIZE(xspi_mux), 0xd0, 9, 0x110, 8, 2, 0xf0, 14, 0 },
+	{ AGILEX72_SDMMC0_SDPHY_REG_CLK, "sdmmc0_sdphy_reg_clk",
+	  lsp_mp_parent, 1, 0xd0, 5, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SDMMC1_SDPHY_REG_CLK, "sdmmc1_sdphy_reg_clk",
+	  lsp_mp_parent, 1, 0xd0, 7, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX72_SDMMC0_SDMCLK, "sdmmc0_sdmclk", memdevice_phy_mux,
+	  ARRAY_SIZE(memdevice_phy_mux), 0xd0, 5, 0x110, 4, 2, 0xf0, 15, 0 },
+	{ AGILEX72_SDMMC1_SDMCLK, "sdmmc1_sdmclk", memdevice_phy_mux,
+	  ARRAY_SIZE(memdevice_phy_mux), 0xd0, 7, 0x110, 6, 2, 0xf0, 15, 0 },
+	{ AGILEX72_SDMMC0_PHY_CLK, "sdmmc0_phy_clk", memdevice_phy_mux,
+	  ARRAY_SIZE(memdevice_phy_mux), 0xd0, 5, 0x110, 4, 2, 0xf0, 15, 0 },
+	{ AGILEX72_SDMMC1_PHY_CLK, "sdmmc1_phy_clk", memdevice_phy_mux,
+	  ARRAY_SIZE(memdevice_phy_mux), 0xd0, 7, 0x110, 6, 2, 0xf0, 15, 0 },
+};
+
+static const struct clk_ops clk_boot_ops = {
+	.recalc_rate = agilex72_boot_clk_recalc_rate,
+	.get_parent = agilex72_boot_get_parent,
+};
+
+static const struct clk_ops clk_gppll_ops = {
+	.recalc_rate = agilex72_clk_pll_recalc_rate,
+	.get_parent = agilex72_clk_pll_get_parent,
+};
+
+static const struct clk_ops peri_c_clk_ops = {
+	.recalc_rate = agilex72_peri_c_clk_recalc_rate,
+	.get_parent = agilex72_peri_c_clk_get_parent,
+};
+
+static const struct clk_ops peri_cnt_clk_ops = {
+	.recalc_rate = agilex72_clk_peri_cnt_clk_recalc_rate,
+	.get_parent = agilex72_clk_periclk_get_parent,
+};
+
+static const struct clk_ops gateclk_ops = {
+	.recalc_rate = agilex72_gate_clk_recalc_rate,
+	.get_parent  = agilex72_gate_get_parent,
+};
+
+static bool agilex72_gate_is_emac(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(gate_clks); i++) {
+		switch (gate_clks[i].id) {
+		case AGILEX72_EMAC0_CLK:
+		case AGILEX72_EMAC1_CLK:
+		case AGILEX72_EMAC2_CLK:
+			if (strcmp(name, gate_clks[i].name) == 0)
+				return true;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return false;
+}
+
+static u8 agilex72_parent_index(const char * const *parents,
+				size_t num_parents, const char *parent_name)
+{
+	for (size_t i = 0; i < num_parents; i++) {
+		if (strcmp(parents[i], parent_name) == 0)
+			return (u8)i;
+	}
+
+	return 0;
+}
+
+static unsigned long agilex72_boot_clk_recalc_rate(struct clk_hw *hwclk,
+						   unsigned long parent_rate)
+{
+	return parent_rate;
+}
+
+static unsigned long agilex72_clk_pll_recalc_rate(struct clk_hw *hwclk,
+						  unsigned long parent_rate)
+{
+	struct agilex72_pll *socfpgaclk =
+		container_of(hwclk, struct agilex72_pll, hw.hw);
+	unsigned long long vco_freq;
+	u32 reg, cr_n_hi, cr_n_lo, crhi_m, n_div, cr_fract_div_ratio;
+	bool bypass;
+
+	reg = readl(socfpgaclk->pll_base + PLL_RATE_REG_OFFSET);
+	bypass = (reg & PLL_CR_BYPASS_DIV_MASK);
+
+	cr_n_hi = reg & PLL_CR_N_HI_MASK;
+	cr_n_lo = (reg & PLL_CR_N_LO_MASK) >> PLL_CR_N_LO_SHIFT;
+	crhi_m  = (reg & PLL_CRHI_M_MASK)  >> PLL_CRHI_M_SHIFT;
+
+	reg = readl(socfpgaclk->pll_base + PLL_FRACT_DIV_REG_OFFSET);
+	cr_fract_div_ratio = reg & PLL_CR_FRACT_DIV_MASK;
+
+	/* 0 represents the value 256. */
+	if (!cr_n_hi)
+		cr_n_hi = 256;
+	if (!cr_n_lo)
+		cr_n_lo = 256;
+
+	n_div = bypass ? 1 : cr_n_lo + cr_n_hi;
+
+	/* bypass: vco = parent_rate * (crhi_m + cr_fract_div_ratio / 2^24) / 1
+	 * normal: vco = parent_rate * (crhi_m + cr_fract_div_ratio / 2^24) / n_div
+	 * Rearranged to avoid floating point:
+	 *   num = parent_rate * (crhi_m * 2^24 + cr_fract_div_ratio)
+	 *   vco = num / (n_div * 2^24)
+	 */
+	vco_freq  = (unsigned long long)parent_rate *
+		    (((unsigned long long)crhi_m << 24) + cr_fract_div_ratio);
+	vco_freq /= (unsigned long long)n_div << 24;
+	return (unsigned long)vco_freq;
+}
+
+static unsigned long agilex72_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
+						     unsigned long parent_rate)
+{
+	struct agilex72_periph_clk *socfpgaclk =
+		container_of(hwclk, struct agilex72_periph_clk, hw.hw);
+	u32 reg, crhi_c, crlo_c, c_div;
+	bool bypass;
+
+	reg    = readl(socfpgaclk->div_reg);
+	bypass = (reg >> socfpgaclk->div_hi_shift) & PLL_CR_BYPASS_DIV_MASK;
+
+	crlo_c = (reg >> socfpgaclk->div_lo_shift) & PLL_CR_C_MASK;
+	crhi_c = (reg >> socfpgaclk->div_hi_shift) & PLL_CR_C_MASK;
+
+	/* 0 represents the value 256. */
+	if (!crhi_c)
+		crhi_c = 256;
+	if (!crlo_c)
+		crlo_c = 256;
+
+	c_div = bypass ? 1 : crhi_c + crlo_c;
+
+	return parent_rate / c_div;
+}
+
+static unsigned long
+agilex72_clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
+				      unsigned long parent_rate)
+{
+	struct agilex72_periph_clk *socfpgaclk;
+	unsigned long div;
+
+	socfpgaclk = container_of(hwclk, struct agilex72_periph_clk, hw.hw);
+	div = readl(socfpgaclk->hw.reg);
+	div &= GENMASK(PERI_CLK_CNT_DIV_WIDTH - 1, 0);
+	div += 1;  /* actual divisor is field_value + 1 */
+
+	return parent_rate / div;
+}
+
+static unsigned long agilex72_gate_clk_recalc_rate(struct clk_hw *hwclk,
+						   unsigned long parent_rate)
+{
+	struct agilex72_gate_clk *socfpgaclk = container_of(hwclk,
+		struct agilex72_gate_clk, hw.hw);
+	u32 div = 1, val;
+
+	if (socfpgaclk->div_reg) {
+		val = readl(socfpgaclk->div_reg) >> socfpgaclk->div_shift;
+		val &= GENMASK(socfpgaclk->div_width - 1, 0);
+		if (socfpgaclk->div_linear)
+			div = val + 1;      /* linear encoding: field_value + 1 */
+		else
+			div = (1 << val);   /* log2 encoding: 2^field_value */
+	}
+	return parent_rate / div;
+}
+
+static u8 agilex72_boot_get_parent(struct clk_hw *hwclk)
+{
+	struct agilex72_pll *socfpgaclk = container_of(hwclk,
+		struct agilex72_pll, hw.hw);
+	u32 pll_src;
+	u8 parent;
+
+	pll_src = readl(socfpgaclk->hw.reg);
+	parent = (pll_src & BOOTCLKSRC_MASK) >> BOOTCLKSRC_SHIFT;
+	return parent;
+}
+
+static u8 agilex72_clk_pll_get_parent(struct clk_hw *hwclk)
+{
+	struct agilex72_pll *socfpgaclk =
+		container_of(hwclk, struct agilex72_pll, hw.hw);
+	u32 pll_src;
+	u8 parent;
+
+	pll_src = readl(socfpgaclk->hw.reg);
+	parent = (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
+		 CLK_MGR_PLL_CLK_SRC_MASK;
+	return parent;
+}
+
+static u8 agilex72_peri_c_clk_get_parent(struct clk_hw *hwclk)
+{
+	/* Peripheral C clocks (GPPLL output clocks) have a single fixed parent
+	 * (the GPPLL itself), so the parent index is always 0.
+	 */
+	return 0;
+}
+
+static u8 agilex72_clk_periclk_get_parent(struct clk_hw *hwclk)
+{
+	struct agilex72_periph_clk *socfpgaclk;
+	u32 clk_src;
+	u8 parent = 0;
+
+	socfpgaclk = container_of(hwclk, struct agilex72_periph_clk, hw.hw);
+
+	if (socfpgaclk->hw.reg) {
+		clk_src = readl(socfpgaclk->hw.reg);
+		parent = (clk_src >> CLK_MGR_FREE_SHIFT) & CLK_MGR_FREE_MASK;
+	}
+	return parent;
+}
+
+static u8 agilex72_gate_get_parent(struct clk_hw *hwclk)
+{
+	struct agilex72_gate_clk *socfpgaclk =
+		container_of(hwclk, struct agilex72_gate_clk, hw.hw);
+	void __iomem *bypass_reg = socfpgaclk->bypass_reg;
+	u32 mask, bypass_val, second_bypass;
+	u8 parent = 0;
+	const char *name = clk_hw_get_name(hwclk);
+
+	if (!bypass_reg)
+		return parent;
+
+	mask = (0x1 << socfpgaclk->bypass_shift);
+	bypass_val = readl(bypass_reg);
+	parent = ((bypass_val & mask) >> socfpgaclk->bypass_shift);
+
+	if (agilex72_gate_is_emac(name)) {
+		/*
+		 * EMAC clocks have a second bypass layer in a register
+		 * EMAC_BYPASS_OFFSET bytes below the main bypass register:
+		 *   bit 0: emaca path is bypassed to boot_clk (only when primary
+		 *          parent selects emaca, i.e. parent == 0)
+		 *   bit 1: emacb path is bypassed to boot_clk (only when primary
+		 *          parent selects emacb, i.e. parent == 1)
+		 */
+		u8 bootclk_bypass =
+			agilex72_parent_index(emac_mux, ARRAY_SIZE(emac_mux),
+					      "boot_clk");
+		/*
+		 * The second EMAC bypass register is always EMAC_BYPASS_OFFSET (0x10)
+		 * below the primary bypass register. For all EMAC clocks the primary
+		 * bypass_reg is regbase+0x100, so this gives regbase+0xf0 which is
+		 * within the mapped clkmgr window.
+		 */
+		second_bypass = readl(bypass_reg - EMAC_BYPASS_OFFSET);
+		if (second_bypass & 0x1)
+			if (parent == 0) /* only applicable if parent is emaca */
+				parent = bootclk_bypass;
+
+		if (second_bypass & 0x2)
+			if (parent == 1) /* only applicable if parent is emacb */
+				parent = bootclk_bypass;
+	}
+
+	return parent;
+}
+
+static struct clk_hw *
+agilex72_register_pll(const struct agilex72_pll_clock *clks,
+		      void __iomem *base, void __iomem *pll_base)
+{
+	struct clk_hw *hw_clk;
+	struct agilex72_pll *pll_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	int ret;
+
+	pll_clk = kzalloc_obj(*pll_clk);
+	if (!pll_clk)
+		return ERR_PTR(-ENOMEM);
+
+	if (strcmp(name, BOOT_CLK) == 0) {
+		init.ops = &clk_boot_ops;
+	} else {
+		pll_clk->pll_base = pll_base;
+		init.ops = &clk_gppll_ops;
+	}
+
+	pll_clk->hw.reg = base + clks->offset;
+
+	init.name = name;
+	init.flags = 0;
+	init.num_parents = clks->num_parents;
+	init.parent_names = clks->parent_names;
+	pll_clk->hw.hw.init = &init;
+	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
+	hw_clk = &pll_clk->hw.hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(pll_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
+static struct clk_hw *
+agilex72_register_periph(const struct agilex72_perip_c_clock *clks,
+			 void __iomem *pll_base)
+{
+	struct agilex72_periph_clk *periph_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	struct clk_hw *hw_clk;
+	int ret;
+
+	periph_clk = kzalloc_obj(*periph_clk);
+	if (!periph_clk)
+		return ERR_PTR(-ENOMEM);
+
+	periph_clk->div_lo_shift = clks->div_lo_shift;
+	periph_clk->div_hi_shift = clks->div_hi_shift;
+	periph_clk->div_reg = pll_base + clks->div_offset;
+	periph_clk->hw.reg  = pll_base;
+
+	init.name = name;
+	init.ops = &peri_c_clk_ops;
+	init.flags = 0;
+
+	init.num_parents = clks->num_parents;
+	init.parent_names = &clks->parent_name;
+
+	periph_clk->hw.hw.init = &init;
+	hw_clk = &periph_clk->hw.hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(periph_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
+static struct clk_hw *
+agilex72_register_cnt_periph(const struct agilex72_perip_cnt_clock *clks,
+			     void __iomem *regbase)
+{
+	struct clk_hw *hw_clk;
+	struct agilex72_periph_clk *periph_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	int ret;
+
+	periph_clk = kzalloc_obj(*periph_clk);
+	if (!periph_clk)
+		return ERR_PTR(-ENOMEM);
+
+	periph_clk->hw.reg = regbase + clks->offset;
+
+	init.name = name;
+	init.ops = &peri_cnt_clk_ops;
+	init.flags = 0;
+	init.num_parents = clks->num_parents;
+	init.parent_names = clks->parent_names;
+	periph_clk->hw.hw.init = &init;
+	hw_clk = &periph_clk->hw.hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(periph_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
+static struct clk_hw *
+agilex72_register_gate(const struct agilex72_gate_clock *clks,
+		       void __iomem *regbase)
+{
+	struct clk_hw *hw_clk;
+	struct agilex72_gate_clk *socfpga_clk;
+	struct clk_init_data init;
+	int ret;
+
+	socfpga_clk = kzalloc_obj(*socfpga_clk);
+	if (!socfpga_clk)
+		return ERR_PTR(-ENOMEM);
+
+	socfpga_clk->hw.reg = regbase + clks->gate_reg;
+	socfpga_clk->hw.bit_idx = clks->gate_idx;
+
+	socfpga_clk->div_linear = clks->div_linear;
+
+	if (clks->div_reg)
+		socfpga_clk->div_reg = regbase + clks->div_reg;
+	else
+		socfpga_clk->div_reg = NULL;
+
+	socfpga_clk->div_width = clks->div_width;
+	socfpga_clk->div_shift = clks->div_offset;
+
+	if (clks->bypass_reg)
+		socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
+	else
+		socfpga_clk->bypass_reg = NULL;
+	socfpga_clk->bypass_shift = clks->bypass_shift;
+
+	init.ops = &gateclk_ops;
+
+	init.name        = clks->name;
+	init.flags       = 0;
+	init.num_parents = clks->num_parents;
+	init.parent_names = clks->parent_names;
+	socfpga_clk->hw.hw.init = &init;
+
+	hw_clk = &socfpga_clk->hw.hw;
+
+	ret = clk_hw_register(NULL, &socfpga_clk->hw.hw);
+	if (ret) {
+		kfree(socfpga_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
+static int
+agilex72_clk_register_cnt_perip(const struct agilex72_perip_cnt_clock *clks,
+				int nums, struct agilex72_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base[0];
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		if (WARN_ON(clks[i].id >= data->clk_data.num)) {
+			pr_err("%s: clock %s id %u out of range (max %u)\n",
+			       __func__, clks[i].name, clks[i].id,
+			       data->clk_data.num);
+			continue;
+		}
+		hw_clk = agilex72_register_cnt_periph(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+static int agilex72_clk_register_gate(const struct agilex72_gate_clock *clks,
+				      int nums, struct agilex72_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base[0];
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		if (WARN_ON(clks[i].id >= data->clk_data.num)) {
+			pr_err("%s: clock %s id %u out of range (max %u)\n",
+			       __func__, clks[i].name, clks[i].id,
+			       data->clk_data.num);
+			continue;
+		}
+		hw_clk = agilex72_register_gate(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+/*
+ * Return the MMIO base address of the GPPLL whose DT resource name matches
+ * @name. The names "gppll0", "gppll1", "gppll2" are the resource names used
+ * in the device tree and map directly to base[1..3] as ioremapped in probe.
+ * Returns NULL for any clock that has no dedicated PLL register block
+ * (e.g. BOOT_CLK, which reuses the main clkmgr window via base[0]).
+ */
+static void __iomem *agilex72_pll_get_regbase(const char *name,
+					      void __iomem * const *base)
+{
+	if (!strcmp(name, "gppll0"))
+		return base[1]; /* gppll0 DT resource */
+	if (!strcmp(name, "gppll1"))
+		return base[2]; /* gppll1 DT resource */
+	if (!strcmp(name, "gppll2"))
+		return base[3]; /* gppll2 DT resource */
+	return NULL;
+}
+
+static int
+agilex72_clk_register_c_perip(const struct agilex72_perip_c_clock *clks,
+			      int nums, struct agilex72_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		if (WARN_ON(clks[i].id >= data->clk_data.num)) {
+			pr_err("%s: clock %s id %u out of range (max %u)\n",
+			       __func__, clks[i].name, clks[i].id,
+			       data->clk_data.num);
+			continue;
+		}
+
+		/*
+		 * clks[i].parent_name holds the name of the parent GPPLL
+		 * (e.g. "gppll0"), which matches the DT resource name and
+		 * therefore the correct MMIO base.
+		 */
+		void __iomem *pll_base =
+			agilex72_pll_get_regbase(clks[i].parent_name, data->base);
+
+		if (!pll_base) {
+			pr_err("%s: no PLL base for clock %s (parent '%s')\n",
+			       __func__, clks[i].name, clks[i].parent_name);
+			continue;
+		}
+		hw_clk = agilex72_register_periph(&clks[i], pll_base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+	return 0;
+}
+
+static int agilex72_clk_register_pll(const struct agilex72_pll_clock *clks,
+				     int nums, struct agilex72_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		if (WARN_ON(clks[i].id >= data->clk_data.num)) {
+			pr_err("%s: clock %s id %u out of range (max %u)\n",
+			       __func__, clks[i].name, clks[i].id,
+			       data->clk_data.num);
+			continue;
+		}
+
+		/* clks[i].name matches the DT resource name for PLL clocks */
+		void __iomem *pll_base =
+			agilex72_pll_get_regbase(clks[i].name, data->base);
+
+		hw_clk = agilex72_register_pll(&clks[i],
+					       data->base[0], pll_base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+static int agilex72_clkmgr_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct agilex72_clock_data *clk_data;
+	void __iomem *base[4];
+	int i, num_clks;
+
+	base[0] = devm_platform_ioremap_resource_byname(pdev, "clkmgr");
+	if (IS_ERR(base[0]))
+		return PTR_ERR(base[0]);
+
+	base[1] = devm_platform_ioremap_resource_byname(pdev, "gppll0");
+	if (IS_ERR(base[1]))
+		return PTR_ERR(base[1]);
+
+	base[2] = devm_platform_ioremap_resource_byname(pdev, "gppll1");
+	if (IS_ERR(base[2]))
+		return PTR_ERR(base[2]);
+
+	base[3] = devm_platform_ioremap_resource_byname(pdev, "gppll2");
+	if (IS_ERR(base[3]))
+		return PTR_ERR(base[3]);
+
+	num_clks = AGILEX72_NUM_CLKS;
+
+	clk_data = devm_kzalloc(dev,
+				struct_size(clk_data, clk_data.hws, num_clks),
+				GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->base[0] = base[0];
+	clk_data->base[1] = base[1];
+	clk_data->base[2] = base[2];
+	clk_data->base[3] = base[3];
+	clk_data->clk_data.num = num_clks;
+
+	for (i = 0; i < num_clks; i++)
+		clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT);
+
+	/*
+	 * Registration order matters: each layer depends on the previous.
+	 *   1. PLLs
+	 *   2. C-peripheral clocks (GPPLL output clocks)
+	 *   3. Cnt-peripheral clocks
+	 *   4. Gate clocks
+	 */
+	agilex72_clk_register_pll(pll_clks, ARRAY_SIZE(pll_clks),
+				  clk_data);
+
+	agilex72_clk_register_c_perip(main_perip_c_clks,
+				      ARRAY_SIZE(main_perip_c_clks),
+					  clk_data);
+
+	agilex72_clk_register_cnt_perip(main_perip_cnt_clks,
+					ARRAY_SIZE(main_perip_cnt_clks),
+					    clk_data);
+
+	agilex72_clk_register_gate(gate_clks,
+				   ARRAY_SIZE(gate_clks), clk_data);
+
+	/*
+	 * usb31_ref_clk is a 1:1 alias of usb31_suspend_clk. The DWC3
+	 * controller uses the same source for both its suspend and reference
+	 * clock inputs on this SoC. Register it as a fixed-factor (passthrough)
+	 * clock so that enabling it propagates to the parent gate without
+	 * touching any gate register of its own.
+	 */
+	clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK] =
+		devm_clk_hw_register_fixed_factor(dev, "usb31_ref_clk",
+						  "usb31_suspend_clk", 0, 1, 1);
+	if (IS_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]))
+		return dev_err_probe(dev,
+			PTR_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]),
+			"failed to register clock usb31_ref_clk\n");
+
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data->clk_data);
+	return 0;
+}
+
+static int agilex72_clkmgr_probe(struct platform_device *pdev)
+{
+	int (*probe_func)(struct platform_device *init_func);
+
+	probe_func = of_device_get_match_data(&pdev->dev);
+	if (!probe_func)
+		return -ENODEV;
+	return probe_func(pdev);
+}
+
+static const struct of_device_id agilex72_clkmgr_match_table[] = {
+	{ .compatible = "altr,agilex72-clkmgr",
+	  .data = agilex72_clkmgr_init },
+	{}
+};
+
+static struct platform_driver agilex72_clkmgr_driver = {
+	.probe		= agilex72_clkmgr_probe,
+	.driver		= {
+		.name	= "agilex72-clkmgr",
+		.suppress_bind_attrs = true,
+		.of_match_table = agilex72_clkmgr_match_table,
+	},
+};
+
+static int __init agilex72_clk_init(void)
+{
+	return platform_driver_register(&agilex72_clkmgr_driver);
+}
+core_initcall(agilex72_clk_init);
diff --git a/drivers/clk/socfpga/clk-agilex72.h b/drivers/clk/socfpga/clk-agilex72.h
new file mode 100644
index 000000000000..e120fe97fd65
--- /dev/null
+++ b/drivers/clk/socfpga/clk-agilex72.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier:    GPL-2.0 */
+/*
+ * Copyright (C) 2026, Altera Corporation
+ */
+
+#ifndef	__AGILEX72_CLK_H
+#define	__AGILEX72_CLK_H
+
+#include <linux/clk-provider.h>
+
+struct agilex72_clock_data {
+	/*
+	 * MMIO bases ioremapped from DT resources with "reg-names" property
+	 * in probe:
+	 *   [0] - "clkmgr"  : main clock manager register block
+	 *   [1] - "gppll0"  : GP PLL 0 register block
+	 *   [2] - "gppll1"  : GP PLL 1 register block
+	 *   [3] - "gppll2"  : GP PLL 2 register block
+	 */
+	void __iomem *base[4];
+
+	/* Must be last */
+	struct clk_hw_onecell_data	clk_data;
+};
+
+struct agilex72_pll {
+	struct clk_gate     hw;
+	void __iomem       *pll_base;
+};
+
+struct agilex72_periph_clk {
+	struct clk_gate  hw;
+	void __iomem    *div_reg;
+	u8               div_lo_shift;
+	u8               div_hi_shift;
+};
+
+struct agilex72_gate_clk {
+	struct clk_gate hw;
+	bool div_linear;
+	void __iomem *div_reg;
+	void __iomem *bypass_reg;
+	u8  div_width;	/* only valid if div_reg != 0 */
+	u8  div_shift;	/* only valid if div_reg != 0 */
+	u8  bypass_shift;      /* only valid if bypass_reg != 0 */
+};
+
+struct agilex72_pll_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	* const *parent_names;
+	u8	num_parents;
+	unsigned long   offset;
+};
+
+struct agilex72_perip_c_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	u8			num_parents;
+	unsigned long		div_offset;
+	u8			div_lo_shift;
+	u8			div_hi_shift;
+	u8			div_lo_width;
+	u8			div_hi_width;
+};
+
+struct agilex72_perip_cnt_clock {
+	unsigned int		id;
+	const char		*name;
+	const char	* const *parent_names;
+	u8			num_parents;
+	unsigned long		offset;
+};
+
+struct agilex72_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char	* const *parent_names;
+	u8			num_parents;
+	unsigned long		gate_reg;
+	u8			gate_idx;
+	unsigned long		div_reg;
+	u8			div_offset;
+	u8			div_width;
+	unsigned long		bypass_reg;
+	u8			bypass_shift;
+	bool			div_linear;
+};
+
+#endif	/* __AGILEX72_CLK_H */
-- 
2.43.7


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

* [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix
  2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
                   ` (2 preceding siblings ...)
  2026-08-06  9:25 ` [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72 evon.chiam
@ 2026-08-06  9:25 ` evon.chiam
  2026-08-06  9:40   ` sashiko-bot
  2026-08-06  9:25 ` [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support evon.chiam
  4 siblings, 1 reply; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

Move the Agilex72 SoC and SoCDK device trees from dts/intel to
dts/altera. Update the board and SoC compatible strings to use
the "altr" vendor.

Signed-off-by: Chiam, Evon <evon.chiam@altera.com>
---
 arch/arm64/boot/dts/altera/Makefile                            | 3 ++-
 arch/arm64/boot/dts/{intel => altera}/socfpga_agilex72.dtsi    | 2 +-
 .../boot/dts/{intel => altera}/socfpga_agilex72_socdk.dts      | 2 +-
 arch/arm64/boot/dts/intel/Makefile                             | 1 -
 4 files changed, 4 insertions(+), 4 deletions(-)
 rename arch/arm64/boot/dts/{intel => altera}/socfpga_agilex72.dtsi (98%)
 rename arch/arm64/boot/dts/{intel => altera}/socfpga_agilex72_socdk.dts (84%)

diff --git a/arch/arm64/boot/dts/altera/Makefile b/arch/arm64/boot/dts/altera/Makefile
index 540bb5ae746b..a1a9ccba5334 100644
--- a/arch/arm64/boot/dts/altera/Makefile
+++ b/arch/arm64/boot/dts/altera/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
-dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_stratix10_socdk.dtb \
+dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex72_socdk.dtb \
+				socfpga_stratix10_socdk.dtb \
 				socfpga_stratix10_socdk_emmc.dtb \
 				socfpga_stratix10_socdk_nand.dtb \
 				socfpga_stratix10_swvp.dtb
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi b/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
similarity index 98%
rename from arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi
rename to arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
index c29c2afcaab7..354c775f577b 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi
+++ b/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
@@ -7,7 +7,7 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
-	compatible = "intel,socfpga-agilex72";
+	compatible = "altr,socfpga-agilex72";
 	#address-cells = <2>;
 	#size-cells = <2>;
 
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
similarity index 84%
rename from arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts
rename to arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
index 998f19f492b3..0959850cff66 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts
+++ b/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
@@ -6,7 +6,7 @@
 
 / {
 	model = "Altera SoCFPGA Agilex72 SoCDK";
-	compatible = "intel,socfpga-agilex72-socdk", "intel,socfpga-agilex72";
+	compatible = "altr,socfpga-agilex72-socdk", "altr,socfpga-agilex72";
 
 	aliases {
 		serial0 = &uart0;
diff --git a/arch/arm64/boot/dts/intel/Makefile b/arch/arm64/boot/dts/intel/Makefile
index 270c70fdf084..088a03b89c99 100644
--- a/arch/arm64/boot/dts/intel/Makefile
+++ b/arch/arm64/boot/dts/intel/Makefile
@@ -8,7 +8,6 @@ dtb-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga_agilex_n6000.dtb \
 				socfpga_agilex5_socdk_013b.dtb \
 				socfpga_agilex5_socdk_modular.dtb \
 				socfpga_agilex5_socdk_nand.dtb \
-				socfpga_agilex72_socdk.dtb \
 				socfpga_agilex7m_socdk.dtb \
 				socfpga_n5x_socdk.dtb
 dtb-$(CONFIG_ARCH_KEEMBAY) += keembay-evm.dtb
-- 
2.43.7


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

* [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support
  2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
                   ` (3 preceding siblings ...)
  2026-08-06  9:25 ` [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix evon.chiam
@ 2026-08-06  9:25 ` evon.chiam
  2026-08-06  9:40   ` sashiko-bot
  4 siblings, 1 reply; 11+ messages in thread
From: evon.chiam @ 2026-08-06  9:25 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dinh Nguyen,
	Michael Turquette, Stephen Boyd
  Cc: Lothar Rubusch, Ng Tze Yee, Nazim Amirul, Adrian Ng Ho Yin,
	Brian Masney, devicetree, linux-clk, linux-kernel

From: "Chiam, Evon" <evon.chiam@altera.com>

Add the Agilex72 clock manager node and input reference clocks, and
wire the UART clocks through the clock manager instead of a fixed
clock. Set the SoCDK board-specific input clock frequencies.

Signed-off-by: Chiam, Evon <evon.chiam@altera.com>
---
 .../boot/dts/altera/socfpga_agilex72.dtsi     | 46 +++++++++++++++++--
 .../dts/altera/socfpga_agilex72_socdk.dts     | 12 +++++
 2 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi b/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
index 354c775f577b..dfc0cfce3d8c 100644
--- a/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
+++ b/arch/arm64/boot/dts/altera/socfpga_agilex72.dtsi
@@ -5,6 +5,7 @@
 /dts-v1/;
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/altr,agilex72-clkmgr.h>
 
 / {
 	compatible = "altr,socfpga-agilex72";
@@ -64,11 +65,38 @@ cpu3: cpu@300 {
 		};
 	};
 
+	/* Clock tree 5 main sources */
 	clocks {
-		uart_clk: uart-clk {
+		cb_intosc_div2_clk: cb-intosc-div2-clk {
+			#clock-cells = <0>;
 			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		cb_intosc_div10_clk: cb-intosc-div10-clk {
 			#clock-cells = <0>;
-			clock-frequency = <125000000>;
+			compatible = "fixed-factor-clock";
+			clocks = <&cb_intosc_div2_clk>;
+			clock-mult = <1>;
+			clock-div = <5>;
+		};
+
+		f2s_free_clk: f2s-free-clk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		osc1: osc1 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		sdm_xspi_clk: sdm-xspi-clk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <200000000>;
 		};
 	};
 
@@ -133,13 +161,23 @@ ocram: sram@0 {
 			#size-cells = <1>;
 		};
 
+		clkmgr: clock-controller@915c000 {
+			compatible = "altr,agilex72-clkmgr";
+			reg = <0x915c000 0x1000>,
+			      <0x915e000 0x1000>,
+			      <0x915f000 0x1000>,
+			      <0x9160000 0x1000>;
+			reg-names = "clkmgr", "gppll0", "gppll1", "gppll2";
+			#clock-cells = <1>;
+		};
+
 		uart0: serial@9038000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x9038000 0x100>;
 			interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
-			clocks = <&uart_clk>;
+			clocks = <&clkmgr AGILEX72_LSP_SP_CLK>;
 			status = "disabled";
 		};
 
@@ -149,7 +187,7 @@ uart1: serial@9039000 {
 			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
-			clocks = <&uart_clk>;
+			clocks = <&clkmgr AGILEX72_LSP_SP_CLK>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
index 0959850cff66..697e694db603 100644
--- a/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
+++ b/arch/arm64/boot/dts/altera/socfpga_agilex72_socdk.dts
@@ -22,6 +22,18 @@ memory@80000000 {
 	};
 };
 
+&cb_intosc_div2_clk {
+	clock-frequency = <500000000>;
+};
+
+&osc1 {
+	clock-frequency = <100000000>;
+};
+
+&f2s_free_clk {
+	clock-frequency = <100000000>;
+};
+
 &uart0 {
 	status = "okay";
 };
-- 
2.43.7


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

* Re: [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix
  2026-08-06  9:25 ` [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix evon.chiam
@ 2026-08-06  9:33   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  9:33 UTC (permalink / raw)
  To: evon.chiam; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] Destructive removal of device tree compatible strings breaks ABI and schema validation.
--

--- Patch [1]: [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix ---
commit 7bb728799feb3a9be3367a121312b26bbd930632
Author: Chiam, Evon <evon.chiam@altera.com>

dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix

Altera has separated from Intel. Update the Agilex72 SoC and board
compatible strings to use the Altera vendor prefix instead of intel.

> diff --git a/Documentation/devicetree/bindings/arm/altera.yaml b/Documentation/devicetree/bindings/arm/altera.yaml
> index 3030cf46fe74c..2ab53cade2fe4 100644
> --- a/Documentation/devicetree/bindings/arm/altera.yaml
> +++ b/Documentation/devicetree/bindings/arm/altera.yaml
> @@ -119,8 +119,8 @@ properties:
>        - description: Agilex72 boards
>          items:
>            - enum:
> -              - intel,socfpga-agilex72-socdk
> -          - const: intel,socfpga-agilex72
> +              - altr,socfpga-agilex72-socdk
> +          - const: altr,socfpga-agilex72

[Severity: Critical]
Does replacing these compatible strings completely rather than retaining the
older strings as deprecated break the ABI for existing bootloaders or
firmware?

Also, will this omission cause validation failures during make dtbs_check?

Looking at the tree, arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi still
uses the removed string:

arch/arm64/boot/dts/intel/socfpga_agilex72.dtsi:

    / {
        compatible = "intel,socfpga-agilex72";

and arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts also continues to
use the removed strings:

arch/arm64/boot/dts/intel/socfpga_agilex72_socdk.dts:

    / {
        model = "Altera SoCFPGA Agilex72 SoCDK";
        compatible = "intel,socfpga-agilex72-socdk", "intel,socfpga-agilex72";

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1786006669.git.evon.chiam@altera.com?part=1

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

* Re: [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding
  2026-08-06  9:25 ` [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding evon.chiam
@ 2026-08-06  9:34   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  9:34 UTC (permalink / raw)
  To: evon.chiam; +Cc: devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The clock manager binding omits the `clocks` and `clock-names` properties, failing to properly model external hardware inputs.
--

--- Patch [2]: [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding ---
commit 99e14dc36681e2c2df411ac60959380ed8376f54
Author: Chiam, Evon <evon.chiam@altera.com>

dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding

Adds the device tree binding and clock ID header for the Altera SoCFPGA
Agilex72 clock manager.

> diff --git a/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml b/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/altr,agilex72-clkmgr.yaml

[ ... ]

> +properties:
> +  compatible:
> +    const: altr,agilex72-clkmgr
> +
> +  reg:

[Severity: Medium]
Should this properties block declare the clocks and clock-names properties?

Because additionalProperties is set to false, any device tree attempting to
properly link the external reference clocks to the clkmgr node via standard
phandles will be rejected by dt_binding_check.

[ ... ]

> +examples:
> +  - |
> +    /* External reference clocks supplied to the clock manager */
> +    clocks {
> +      cb_intosc_div2_clk: cb-intosc-div2-clk {
> +        #clock-cells = <0>;

[ ... ]

> +    clkmgr: clock-controller@915c000 {
> +      compatible = "altr,agilex72-clkmgr";
> +      reg = <0x915c000 0x1000>,
> +            <0x915e000 0x1000>,
> +            <0x915f000 0x1000>,
> +            <0x9160000 0x1000>;
> +      reg-names = "clkmgr", "gppll0", "gppll1", "gppll2";
> +      #clock-cells = <1>;
> +    };
> +...

[Severity: Medium]
Does this example accurately reflect the hardware topology?

The external reference clocks are defined just above this node, but the
clkmgr node does not consume them. While older bindings relied on global
fixed-clock lookups by name, newer schemas typically declare their
external clock inputs to support accurate topological representation and
potential parent clock power management.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1786006669.git.evon.chiam@altera.com?part=2

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

* Re: [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72
  2026-08-06  9:25 ` [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72 evon.chiam
@ 2026-08-06  9:38   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  9:38 UTC (permalink / raw)
  To: evon.chiam; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] The `struct clk_init_data init` variable is declared on the stack without zero-initialization, leaving fields like `parent_data` and `parent_hws` containing uninitialized garbage.
- [High] The `gateclk_ops` structure lacks `.enable`, `.disable`, and `.is_enabled` callbacks, rendering software clock gating completely non-functional.
- [High] Independent clocks `dma_0_core_clk` and `dma_0_hs_clk` are registered with the exact same hardware gate register and bit, leading to uncoordinated hardware state changes.
- [High] Probe error paths leak `kzalloc_obj` memory and leave non-devm clocks registered with the CCF, containing dangling `__iomem` pointers that lead to Use-After-Free.
--

--- Patch [3]: [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72 ---
commit fb18cfcc77d7e1e9f2bfe18c6b8c94bdd0fbad23
Author: Chiam, Evon <evon.chiam@altera.com>
Subject: clk: socfpga: agilex72: add clock manager driver for Agilex72

This commit adds a new clock manager driver to support the Altera Agilex72
platform.

> diff --git a/drivers/clk/socfpga/clk-agilex72.c b/drivers/clk/socfpga/clk-agilex72.c
> new file mode 100644
> index 0000000000000..e350d8a9bb4d9
> --- /dev/null
> +++ b/drivers/clk/socfpga/clk-agilex72.c

[ ... ]

> +static const struct clk_ops gateclk_ops = {
> +	.recalc_rate = agilex72_gate_clk_recalc_rate,
> +	.get_parent  = agilex72_gate_get_parent,
> +};

[Severity: High]
Are the .enable, .disable, and .is_enabled callbacks intentionally missing
here?

Without these hooks, clk_enable() and clk_disable() calls will return
success without actually writing to the hardware gate registers, leaving the
physical clock ungated or gated incorrectly.

[ ... ]

> +	{ AGILEX72_DMA_0_CORE_CLK, "dma_0_core_clk", lsp_main_parent,
> +	  1, 0xd0, 15, 0, 0, 0, 0, 0, 0 },
> +	{ AGILEX72_DMA_0_HS_CLK, "dma_0_hs_clk", lsp_mp_parent,
> +	  1, 0xd0, 15, 0, 0, 0, 0, 0, 0 },
> +	{ AGILEX72_DMA_1_CORE_CLK, "dma_1_core_clk", lsp_main_parent,
> +	  1, 0xd0, 16, 0, 0, 0, 0, 0, 0 },
> +	{ AGILEX72_DMA_1_HS_CLK, "dma_1_hs_clk", lsp_mp_parent,
> +	  1, 0xd0, 16, 0, 0, 0, 0, 0, 0 },

[Severity: High]
Will mapping independent clocks to the exact same hardware gate register
and bit cause uncoordinated state changes?

The dma_0_core_clk and dma_0_hs_clk both map to register 0xd0, bit index 15.
Because they are registered as entirely distinct clk_hw instances, if
two consumer paths enable both clocks and one path later disables its clock,
the reference count for that specific clock drops to 0. This clears bit 15,
instantaneously cutting off the clock for the other active consumer.

The same conflict appears to occur for dma_1_core_clk and dma_1_hs_clk on
bit 16.

[ ... ]

> +static struct clk_hw *
> +agilex72_register_pll(const struct agilex72_pll_clock *clks,
> +		      void __iomem *base, void __iomem *pll_base)
> +{
> +	struct clk_hw *hw_clk;
> +	struct agilex72_pll *pll_clk;
> +	struct clk_init_data init;
> +	const char *name = clks->name;
> +	int ret;

[Severity: Critical]
Does this leave the init structure partially uninitialized on the stack?

Because init is not zero-initialized, fields like parent_data and parent_hws
might contain uninitialized stack memory. When passed to clk_hw_register(),
the clock framework might check these garbage values and attempt to dereference
them.

This same pattern appears in agilex72_register_periph(),
agilex72_register_cnt_periph(), and agilex72_register_gate().

[ ... ]

> +static struct clk_hw *
> +agilex72_register_gate(const struct agilex72_gate_clock *clks,
> +		       void __iomem *regbase)
> +{
> +	struct clk_hw *hw_clk;
> +	struct agilex72_gate_clk *socfpga_clk;
> +	struct clk_init_data init;
> +	int ret;
> +
> +	socfpga_clk = kzalloc_obj(*socfpga_clk);
> +	if (!socfpga_clk)
> +		return ERR_PTR(-ENOMEM);
> +
> +	socfpga_clk->hw.reg = regbase + clks->gate_reg;
> +	socfpga_clk->hw.bit_idx = clks->gate_idx;

[Severity: High]
If the gateclk_ops are updated to use standard gate operations, will this
cause a null pointer dereference?

The hw.lock spinlock assignment for struct clk_gate is missing here.

[ ... ]

> +	clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK] =
> +		devm_clk_hw_register_fixed_factor(dev, "usb31_ref_clk",
> +						  "usb31_suspend_clk", 0, 1, 1);
> +	if (IS_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]))
> +		return dev_err_probe(dev,
> +			PTR_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]),
> +			"failed to register clock usb31_ref_clk\n");

[Severity: High]
Does this error path leak memory and leave dangling clock registrations
if devm_clk_hw_register_fixed_factor() fails?

The earlier clocks are allocated with kzalloc_obj() and registered using
clk_hw_register(NULL, ...), which bypasses automatic devres cleanup. If this
returns an error, devres will automatically unmap the MMIO resources, but
the clocks remain registered.

If a tool like debugfs clk_summary attempts to access the still-registered
clocks, the framework will invoke driver callbacks that read from the unmapped
memory, resulting in a synchronous external abort. Could we add proper
unregister calls on the error path, or use devm_clk_hw_register() for all
clocks?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1786006669.git.evon.chiam@altera.com?part=3

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

* Re: [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix
  2026-08-06  9:25 ` [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix evon.chiam
@ 2026-08-06  9:40   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  9:40 UTC (permalink / raw)
  To: evon.chiam; +Cc: conor+dt, robh, devicetree

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The clock operations struct for gate clocks (`gateclk_ops`) completely omits enablement functions, rendering the hardware clock gates unmanageable by the OS.
--

--- Patch [4]: [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix ---
commit fb18cfcc77d7e1e9f2bfe18c6b8c94bdd0fbad23
Author: Chiam, Evon <evon.chiam@altera.com>

clk: socfpga: agilex72: add clock manager driver for Agilex72

Add new Clock manager driver to support new Altera Agilex72 platform

> diff --git a/drivers/clk/socfpga/clk-agilex72.c b/drivers/clk/socfpga/clk-agilex72.c
> new file mode 100644
> index 0000000000000..e350d8a9bb4d9
> --- /dev/null
> +++ b/drivers/clk/socfpga/clk-agilex72.c
> @@ -0,0 +1,1181 @@
[ ... ]
> +static const struct clk_ops peri_cnt_clk_ops = {
> +	.recalc_rate = agilex72_clk_peri_cnt_clk_recalc_rate,
> +	.get_parent = agilex72_clk_periclk_get_parent,
> +};
> +
> +static const struct clk_ops gateclk_ops = {
> +	.recalc_rate = agilex72_gate_clk_recalc_rate,
> +	.get_parent  = agilex72_gate_get_parent,
> +};

[Severity: High]
Does this code prevent hardware clock gates from being managed by the OS?

The clock framework relies on the .enable, .disable, and .is_enabled
callbacks in clk_ops to manage hardware state. Because they are missing
from gateclk_ops, calls like clk_enable() will silently succeed without
modifying the hardware.

If a peripheral's clock was disabled by the bootloader, it will remain off,
causing the peripheral driver to fail or the system to panic when unclocked
registers are accessed. Conversely, unused clocks cannot be turned off.

[ ... ]
> +static struct clk_hw *
> +agilex72_register_gate(const struct agilex72_gate_clock *clks,
> +		       void __iomem *regbase)
> +{
[ ... ]
> +	if (clks->bypass_reg)
> +		socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
> +	else
> +		socfpga_clk->bypass_reg = NULL;
> +	socfpga_clk->bypass_shift = clks->bypass_shift;
> +
> +	init.ops = &gateclk_ops;

[Severity: High]
Can these callbacks be added so that hardware state is correctly modified?

This assigns the incomplete ops struct to all software-gated clocks.
This occurs every time a peripheral driver calls clk_prepare_enable() or
clk_disable_unprepare() on any of the SW gate clocks registered by
agilex72_register_gate().

> +
> +	init.name        = clks->name;
> +	init.flags       = 0;
> +	init.num_parents = clks->num_parents;
> +	init.parent_names = clks->parent_names;
> +	socfpga_clk->hw.hw.init = &init;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1786006669.git.evon.chiam@altera.com?part=4

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

* Re: [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support
  2026-08-06  9:25 ` [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support evon.chiam
@ 2026-08-06  9:40   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  9:40 UTC (permalink / raw)
  To: evon.chiam; +Cc: robh, conor+dt, devicetree

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Clock gate operations (.enable, .disable, .is_enabled) are missing from gateclk_ops, rendering clock gating non-functional.
- [High] Probe error path leaves non-devm clocks registered with CCF while their backing MMIO regions are unmapped, leading to a use-after-free panic.
--

--- Patch [5]: [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support ---
commit 9ede61d9f11826e0bfb7cdf0bab36155fec8e509
Author: Chiam, Evon <evon.chiam@altera.com>

arm64: dts: altera: agilex72: add clock manager support

Add the Agilex72 clock manager node and input reference clocks, and
wire the UART clocks through the clock manager instead of a fixed
clock. Set the SoCDK board-specific input clock frequencies.

> diff --git a/drivers/clk/socfpga/clk-agilex72.c b/drivers/clk/socfpga/clk-agilex72.c
> new file mode 100644
> index 0000000000000..e350d8a9bb4d9
> --- /dev/null
> +++ b/drivers/clk/socfpga/clk-agilex72.c
> @@ -0,0 +1,1181 @@
[ ... ]
> +static const struct clk_ops peri_cnt_clk_ops = {
> +	.recalc_rate = agilex72_clk_peri_cnt_clk_recalc_rate,
> +	.get_parent = agilex72_clk_periclk_get_parent,
> +};
> +
> +static const struct clk_ops gateclk_ops = {
> +	.recalc_rate = agilex72_gate_clk_recalc_rate,
> +	.get_parent  = agilex72_gate_get_parent,
> +};

[Severity: High]
Since gateclk_ops omits the standard clock gating callbacks like .enable,
.disable, and .is_enabled, won't this prevent the kernel from toggling hardware
gates?

If a peripheral's clock was disabled by the bootloader, calling
clk_prepare_enable() from a driver will silently return success without
modifying the hardware. Subsequent register accesses to that peripheral could
trigger a synchronous external abort.

[ ... ]
> +	init.ops = &gateclk_ops;
> +
> +	init.name        = clks->name;
> +	init.flags       = 0;
> +	init.num_parents = clks->num_parents;
> +	init.parent_names = clks->parent_names;
> +	socfpga_clk->hw.hw.init = &init;
> +
> +	hw_clk = &socfpga_clk->hw.hw;
> +
> +	ret = clk_hw_register(NULL, &socfpga_clk->hw.hw);
> +	if (ret) {
> +		kfree(socfpga_clk);
> +		return ERR_PTR(ret);
> +	}
> +	return hw_clk;
> +}

[Severity: High]
Individual clocks are registered into the Common Clock Framework using
clk_hw_register() here without being tied to the device's devres lifecycle.

If devm_clk_hw_register_fixed_factor() fails later during
agilex72_clkmgr_init(), the probe will abort and the devres framework will
automatically unmap the MMIO bases.

However, these non-devm clocks registered earlier will not be unregistered.
Could this leave dangling pointers in the CCF?

[ ... ]
> +	/*
> +	 * usb31_ref_clk is a 1:1 alias of usb31_suspend_clk. The DWC3
> +	 * controller uses the same source for both its suspend and reference
> +	 * clock inputs on this SoC. Register it as a fixed-factor (passthrough)
> +	 * clock so that enabling it propagates to the parent gate without
> +	 * touching any gate register of its own.
> +	 */
> +	clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK] =
> +		devm_clk_hw_register_fixed_factor(dev, "usb31_ref_clk",
> +						  "usb31_suspend_clk", 0, 1, 1);
> +	if (IS_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]))
> +		return dev_err_probe(dev,
> +			PTR_ERR(clk_data->clk_data.hws[AGILEX72_USB31_REF_CLK]),
> +			"failed to register clock usb31_ref_clk\n");

[Severity: High]
This error path fails the probe without unregistering the previously registered
non-devm clocks.

If CCF later walks the clock tree (e.g., via a read of
/sys/kernel/debug/clk/clk_summary), it will invoke the .recalc_rate callbacks
of these leaked clocks. Those callbacks will dereference the now-unmapped memory
pointers, causing an external abort/kernel panic.

Is there a way to unregister them to avoid leaving dangling pointers, or should
devm_clk_hw_register() be used for all clocks?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1786006669.git.evon.chiam@altera.com?part=5

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

end of thread, other threads:[~2026-08-06  9:40 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06  9:25 [PATCH 0/5] clk: socfpga: add Agilex72 clock manager support evon.chiam
2026-08-06  9:25 ` [PATCH 1/5] dt-bindings: arm: altera: fix Agilex72 compatible vendor prefix evon.chiam
2026-08-06  9:33   ` sashiko-bot
2026-08-06  9:25 ` [PATCH 2/5] dt-bindings: clock: altr,agilex72-clkmgr: add Agilex72 clock manager binding evon.chiam
2026-08-06  9:34   ` sashiko-bot
2026-08-06  9:25 ` [PATCH 3/5] clk: socfpga: agilex72: add clock manager driver for Agilex72 evon.chiam
2026-08-06  9:38   ` sashiko-bot
2026-08-06  9:25 ` [PATCH 4/5] arm64: dts: altera: move Agilex72 DT and use altr prefix evon.chiam
2026-08-06  9:40   ` sashiko-bot
2026-08-06  9:25 ` [PATCH 5/5] arm64: dts: altera: agilex72: add clock manager support evon.chiam
2026-08-06  9:40   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox