linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] add Amlogic A1 clock controller driver
@ 2019-10-18  7:14 Jian Hu
  2019-10-18  7:14 ` [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Jian Hu @ 2019-10-18  7:14 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

add support for Amlogic A1 clock driver, the clock includes 
three parts: peripheral clocks, pll clocks, CPU clocks.
sys pll and CPU clocks will be sent in next patch.

Changes since v1 at [1]:
-place A1 config alphabetically
-add actual reason for RO ops, CLK_IS_CRITICAL, CLK_IGNORE_UNUSED
-separate the driver into two driver: peripheral and pll driver
-delete CLK_IGNORE_UNUSED flag for pwm b/c/d/e/f clock, dsp clock
-delete the change in Kconfig.platforms, address to Kevin alone
-remove the useless comments
-modify the meson pll driver to support A1 PLLs

[1] https://lkml.kernel.org/r/1569411888-98116-1-git-send-email-jian.hu@amlogic.com

Jian Hu (3):
  dt-bindings: clock: meson: add A1 clock controller bindings
  clk: meson: add support for A1 PLL clock ops
  clk: meson: a1: add support for Amlogic A1 clock driver

 .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  143 ++
 drivers/clk/meson/Kconfig                          |   10 +
 drivers/clk/meson/Makefile                         |    1 +
 drivers/clk/meson/a1-pll.c                         |  345 +++
 drivers/clk/meson/a1-pll.h                         |   56 +
 drivers/clk/meson/a1.c                             | 2264 ++++++++++++++++++++
 drivers/clk/meson/a1.h                             |  120 ++
 drivers/clk/meson/clk-pll.c                        |   66 +-
 drivers/clk/meson/clk-pll.h                        |    1 +
 include/dt-bindings/clock/a1-clkc.h                |   98 +
 include/dt-bindings/clock/a1-pll-clkc.h            |   16 +
 11 files changed, 3114 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
 create mode 100644 drivers/clk/meson/a1-pll.c
 create mode 100644 drivers/clk/meson/a1-pll.h
 create mode 100644 drivers/clk/meson/a1.c
 create mode 100644 drivers/clk/meson/a1.h
 create mode 100644 include/dt-bindings/clock/a1-clkc.h
 create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h

-- 
1.9.1


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

* [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-10-18  7:14 [PATCH v2 0/3] add Amlogic A1 clock controller driver Jian Hu
@ 2019-10-18  7:14 ` Jian Hu
  2019-10-21 10:43   ` Jerome Brunet
  2019-10-18  7:14 ` [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops Jian Hu
  2019-10-18  7:14 ` [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
  2 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-10-18  7:14 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

Add the documentation to support Amlogic A1 clock driver,
and add A1 clock controller bindings.

Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
 .../devicetree/bindings/clock/amlogic,a1-clkc.yaml | 143 +++++++++++++++++++++
 include/dt-bindings/clock/a1-clkc.h                |  98 ++++++++++++++
 include/dt-bindings/clock/a1-pll-clkc.h            |  16 +++
 3 files changed, 257 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
 create mode 100644 include/dt-bindings/clock/a1-clkc.h
 create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
new file mode 100644
index 0000000..b382eebe
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/clock/amlogic,a1-clkc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson A/C serials Clock Control Unit Device Tree Bindings
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+  - Jerome Brunet <jbrunet@baylibre.com>
+  - Jian Hu <jian.hu@jian.hu.com>
+
+description: |+
+  The clock controller node should be the child of a syscon node with the
+  required property:
+
+  - compatible:         Should be one of the following:
+                        "amlogic,meson-a-analog-sysctrl", "syscon", "simple-mfd"
+                        "amlogic,meson-a-periphs-sysctrl", "syscon", "simple-mfd"
+
+  Refer to the the bindings described in
+  Documentation/devicetree/bindings/mfd/syscon.txt
+
+properties:
+  "#clock-cells":
+    const: 1
+  compatible:
+    - enum:
+        - amlogic,a1-periphs-clkc
+        - amlogic,a1-pll-clkc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 2
+    maxItems: 6
+
+  clock-names:
+    minItems: 2
+    maxItems: 6
+
+required:
+  - "#clock-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+if:
+  properties:
+    compatible:
+      enum:
+        - amlogic,a1-periphs-clkc
+
+then:
+  properties:
+    clocks:
+      minItems: 2
+      maxItems: 2
+    items:
+     - description: fixed pll gate clock
+     - description: hifi pll gate clock
+
+    clock-names:
+      minItems: 2
+      maxItems: 2
+      items:
+        - const: xtal_fixpll
+        - const: xtal_hifipll
+
+else:
+  if:
+    properties:
+      compatible:
+        const: amlogic,a1-pll-clkc
+
+  then:
+    properties:
+      clocks:
+        minItems: 6
+        maxItems: 6
+        items:
+         - description: Input fixed pll div2
+         - description: Input fixed pll div3
+         - description: Input fixed pll div5
+         - description: Input fixed pll div7
+         - description: Periph Hifi pll
+         - description: Input Oscillator (usually at 24MHz)
+
+      clock-names:
+        minItems: 6
+        maxItems: 6
+        items:
+         - const: fclk_div2
+         - const: fclk_div3
+         - const: fclk_div5
+         - const: fclk_div7
+         - const: hifi_pll
+         - const: xtal
+
+
+additionalProperties: false
+
+examples:
+  - |
+    analog: system-controller@0 {
+        compatible = "amlogic,meson-a-analog-sysctrl",
+                     "simple-mfd", "syscon";
+        reg = <0 0x7c00 0 0x21c>;
+
+        clkc_pll: pll-clock-controller {
+                compatible = "amlogic,a1-pll-clkc";
+                #clock-cells = <1>;
+                clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
+                         <&clkc_periphs CLKID_XTAL_HIFIPLL>;
+                clock-names = "xtal_fixpll", "xtal_hifipll";
+        };
+    };
+
+  - |
+    periphs: system-controller@1 {
+        compatible = "amlogic,meson-a-periphs-sysctrl",
+                     "simple-mfd", "syscon";
+        reg = <0 0x800 0 0x104>;
+
+        clkc_periphs: periphs-clock-controller {
+                compatible = "amlogic,a1-periphs-clkc";
+                #clock-cells = <1>;
+                clocks = <&clkc_pll CLKID_FCLK_DIV2>,
+                        <&clkc_pll CLKID_FCLK_DIV3>,
+                        <&clkc_pll CLKID_FCLK_DIV5>,
+                        <&clkc_pll CLKID_FCLK_DIV7>,
+                        <&clkc_pll CLKID_HIFI_PLL>,
+                        <&xtal>;
+                clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
+                              "fclk_div7", "hifi_pll", "xtal";
+        };
+    };
diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h
new file mode 100644
index 0000000..1ba0112
--- /dev/null
+++ b/include/dt-bindings/clock/a1-clkc.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __A1_CLKC_H
+#define __A1_CLKC_H
+
+#define CLKID_XTAL_FIXPLL			1
+#define CLKID_XTAL_USB_PHY			2
+#define CLKID_XTAL_USB_CTRL			3
+#define CLKID_XTAL_HIFIPLL			4
+#define CLKID_XTAL_SYSPLL			5
+#define CLKID_XTAL_DDS				6
+#define CLKID_SYS_CLK				7
+#define CLKID_CLKTREE				8
+#define CLKID_RESET_CTRL			9
+#define CLKID_ANALOG_CTRL			10
+#define CLKID_PWR_CTRL				11
+#define CLKID_PAD_CTRL				12
+#define CLKID_SYS_CTRL				13
+#define CLKID_TEMP_SENSOR			14
+#define CLKID_AM2AXI_DIV			15
+#define CLKID_SPICC_B				16
+#define CLKID_SPICC_A				17
+#define CLKID_CLK_MSR				18
+#define CLKID_AUDIO				19
+#define CLKID_JTAG_CTRL				20
+#define CLKID_SARADC				21
+#define CLKID_PWM_EF				22
+#define CLKID_PWM_CD				23
+#define CLKID_PWM_AB				24
+#define CLKID_CEC				25
+#define CLKID_I2C_S				26
+#define CLKID_IR_CTRL				27
+#define CLKID_I2C_M_D				28
+#define CLKID_I2C_M_C				29
+#define CLKID_I2C_M_B				30
+#define CLKID_I2C_M_A				31
+#define CLKID_ACODEC				32
+#define CLKID_OTP				33
+#define CLKID_SD_EMMC_A				34
+#define CLKID_USB_PHY				35
+#define CLKID_USB_CTRL				36
+#define CLKID_SYS_DSPB				37
+#define CLKID_SYS_DSPA				38
+#define CLKID_DMA				39
+#define CLKID_IRQ_CTRL				40
+#define CLKID_NIC				41
+#define CLKID_GIC				42
+#define CLKID_UART_C				43
+#define CLKID_UART_B				44
+#define CLKID_UART_A				45
+#define CLKID_SYS_PSRAM				46
+#define CLKID_RSA				47
+#define CLKID_CORESIGHT				48
+#define CLKID_AM2AXI_VAD			49
+#define CLKID_AUDIO_VAD				50
+#define CLKID_AXI_DMC				51
+#define CLKID_AXI_PSRAM				52
+#define CLKID_RAMB				53
+#define CLKID_RAMA				54
+#define CLKID_AXI_SPIFC				55
+#define CLKID_AXI_NIC				56
+#define CLKID_AXI_DMA				57
+#define CLKID_CPU_CTRL				58
+#define CLKID_ROM				59
+#define CLKID_PROC_I2C				60
+#define CLKID_DSPA_SEL				61
+#define CLKID_DSPB_SEL				62
+#define CLKID_DSPA_EN_DSPA			63
+#define CLKID_DSPA_EN_NIC			64
+#define CLKID_DSPB_EN_DSPB			65
+#define CLKID_DSPB_EN_NIC			66
+#define CLKID_RTC_CLK				67
+#define CLKID_CECA_32K				68
+#define CLKID_CECB_32K				69
+#define CLKID_24M				70
+#define CLKID_12M				71
+#define CLKID_FCLK_DIV2_DIVN			72
+#define CLKID_GEN				73
+#define CLKID_SARADC_SEL			74
+#define CLKID_SARADC_CLK			75
+#define CLKID_PWM_A				76
+#define CLKID_PWM_B				77
+#define CLKID_PWM_C				78
+#define CLKID_PWM_D				79
+#define CLKID_PWM_E				80
+#define CLKID_PWM_F				81
+#define CLKID_SPICC				82
+#define CLKID_TS				83
+#define CLKID_SPIFC				84
+#define CLKID_USB_BUS				85
+#define CLKID_SD_EMMC				86
+#define CLKID_PSRAM				87
+#define CLKID_DMC				88
+
+#endif /* __A1_CLKC_H */
diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
new file mode 100644
index 0000000..58eae23
--- /dev/null
+++ b/include/dt-bindings/clock/a1-pll-clkc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __A1_PLL_CLKC_H
+#define __A1_PLL_CLKC_H
+
+#define CLKID_FIXED_PLL				1
+#define CLKID_FCLK_DIV2				6
+#define CLKID_FCLK_DIV3				7
+#define CLKID_FCLK_DIV5				8
+#define CLKID_FCLK_DIV7				9
+#define CLKID_HIFI_PLL				10
+
+#endif /* __A1_PLL_CLKC_H */
-- 
1.9.1


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

* [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops
  2019-10-18  7:14 [PATCH v2 0/3] add Amlogic A1 clock controller driver Jian Hu
  2019-10-18  7:14 ` [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
@ 2019-10-18  7:14 ` Jian Hu
  2019-10-21 11:31   ` Jerome Brunet
  2019-10-18  7:14 ` [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
  2 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-10-18  7:14 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

The A1 PLL design is different with previous SoCs. The PLL
internal analog modules Power-on sequence is different
with previous, and thus requires a strict register sequence to
enable the PLL. Unlike the previous series, the maximum frequency
is 6G in G12A, for A1 the maximum is 1536M.

Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
 drivers/clk/meson/clk-pll.c | 66 ++++++++++++++++++++++++++++++++++++++++-----
 drivers/clk/meson/clk-pll.h |  1 +
 2 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
index ddb1e56..b440e62 100644
--- a/drivers/clk/meson/clk-pll.c
+++ b/drivers/clk/meson/clk-pll.c
@@ -349,6 +349,56 @@ static void meson_clk_pll_disable(struct clk_hw *hw)
 	meson_parm_write(clk->map, &pll->en, 0);
 }
 
+/*
+ * The A1 design is different with previous SoCs.The PLL
+ * internal analog modules Power-on sequence is different with
+ * previous, different PLL has the different sequence, and
+ * thus requires a strict register sequence to enable the PLL.
+ * When set a new target frequency, the sequence should keep
+ * the same with the initial sequence. Unlike the previous series,
+ * the maximum frequency is 6G in G12A, for A1 the maximum
+ * is 1536M.
+ */
+static void meson_params_update_with_init_seq(struct clk_regmap *clk,
+				       struct meson_clk_pll_data *pll,
+				       unsigned int m, unsigned int n,
+				       unsigned int frac)
+{
+	struct parm *pm = &pll->m;
+	struct parm *pn = &pll->n;
+	struct parm *pfrac = &pll->frac;
+	const struct reg_sequence *init_regs = pll->init_regs;
+	unsigned int i, val;
+
+	for (i = 0; i < pll->init_count; i++) {
+		if (pn->reg_off == init_regs[i].reg) {
+			/* Clear M N bits and Update M N value */
+			val = init_regs[i].def;
+			val &= CLRPMASK(pn->width, pn->shift);
+			val &= CLRPMASK(pm->width, pm->shift);
+			val |= n << pn->shift;
+			val |= m << pm->shift;
+			regmap_write(clk->map, pn->reg_off, val);
+		} else if (MESON_PARM_APPLICABLE(&pll->frac) &&
+			   (pfrac->reg_off == init_regs[i].reg)) {
+			/* Clear Frac bits and Update Frac value */
+			val = init_regs[i].def;
+			val &= CLRPMASK(pfrac->width, pfrac->shift);
+			val |= frac << pfrac->shift;
+			regmap_write(clk->map, pfrac->reg_off, val);
+		} else {
+			/*
+			 * According to the PLL hardware constraint,
+			 * the left registers should be setted again.
+			 */
+			val = init_regs[i].def;
+			regmap_write(clk->map, init_regs[i].reg, val);
+		}
+		if (init_regs[i].delay_us)
+			udelay(init_regs[i].delay_us);
+	}
+}
+
 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 				  unsigned long parent_rate)
 {
@@ -366,16 +416,20 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 	if (ret)
 		return ret;
 
+	if (MESON_PARM_APPLICABLE(&pll->frac))
+		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
+
 	enabled = meson_parm_read(clk->map, &pll->en);
 	if (enabled)
 		meson_clk_pll_disable(hw);
 
-	meson_parm_write(clk->map, &pll->n, n);
-	meson_parm_write(clk->map, &pll->m, m);
-
-	if (MESON_PARM_APPLICABLE(&pll->frac)) {
-		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
-		meson_parm_write(clk->map, &pll->frac, frac);
+	if (pll->strict_sequence)
+		meson_params_update_with_init_seq(clk, pll, m, n, frac);
+	else {
+		meson_parm_write(clk->map, &pll->n, n);
+		meson_parm_write(clk->map, &pll->m, m);
+		if (MESON_PARM_APPLICABLE(&pll->frac))
+			meson_parm_write(clk->map, &pll->frac, frac);
 	}
 
 	/* If the pll is stopped, bail out now */
diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h
index 367efd0..d5789cef 100644
--- a/drivers/clk/meson/clk-pll.h
+++ b/drivers/clk/meson/clk-pll.h
@@ -41,6 +41,7 @@ struct meson_clk_pll_data {
 	const struct pll_params_table *table;
 	const struct pll_mult_range *range;
 	u8 flags;
+	bool strict_sequence;
 };
 
 extern const struct clk_ops meson_clk_pll_ro_ops;
-- 
1.9.1


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

* [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-18  7:14 [PATCH v2 0/3] add Amlogic A1 clock controller driver Jian Hu
  2019-10-18  7:14 ` [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
  2019-10-18  7:14 ` [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops Jian Hu
@ 2019-10-18  7:14 ` Jian Hu
  2019-10-21 11:41   ` Jerome Brunet
  2 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-10-18  7:14 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel

The Amlogic A1 clock includes three drivers:
peripheral clocks, pll clocks, CPU clocks.
sys pll and CPU clocks will be sent in next patch.

Unlike the previous series, there is no EE/AO domain
in A1 CLK controllers.

Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
 drivers/clk/meson/Kconfig  |   10 +
 drivers/clk/meson/Makefile |    1 +
 drivers/clk/meson/a1-pll.c |  345 +++++++
 drivers/clk/meson/a1-pll.h |   56 ++
 drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/a1.h     |  120 +++
 6 files changed, 2796 insertions(+)
 create mode 100644 drivers/clk/meson/a1-pll.c
 create mode 100644 drivers/clk/meson/a1-pll.h
 create mode 100644 drivers/clk/meson/a1.c
 create mode 100644 drivers/clk/meson/a1.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index dabeb43..c2809b2 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
 	  Support for the audio clock controller on AmLogic A113D devices,
 	  aka axg, Say Y if you want audio subsystem to work.
 
+config COMMON_CLK_A1
+	bool
+	depends on ARCH_MESON
+	select COMMON_CLK_MESON_REGMAP
+	select COMMON_CLK_MESON_DUALDIV
+	select COMMON_CLK_MESON_PLL
+	help
+	  Support for the clock controller on Amlogic A113L device,
+	  aka a1. Say Y if you want peripherals to work.
+
 config COMMON_CLK_G12A
 	bool
 	depends on ARCH_MESON
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 3939f21..28cbae1 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
 
 obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
 obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
+obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
 obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
 obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
new file mode 100644
index 0000000..486d964
--- /dev/null
+++ b/drivers/clk/meson/a1-pll.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ */
+
+#include <linux/platform_device.h>
+#include "clk-pll.h"
+#include "meson-eeclk.h"
+#include "a1-pll.h"
+
+static struct clk_regmap a1_fixed_pll_dco = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = ANACTRL_FIXPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = ANACTRL_FIXPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = ANACTRL_FIXPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.frac = {
+			.reg_off = ANACTRL_FIXPLL_CTRL1,
+			.shift   = 0,
+			.width   = 19,
+		},
+		.l = {
+			.reg_off = ANACTRL_FIXPLL_CTRL0,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.rst = {
+			.reg_off = ANACTRL_FIXPLL_CTRL0,
+			.shift   = 29,
+			.width   = 1,
+		},
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fixed_pll_dco",
+		.ops = &meson_clk_pll_ro_ops,
+		.parent_data = &(const struct clk_parent_data){
+			.fw_name = "xtal_fixpll",
+			.name = "xtal_fixpll",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fixed_pll = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANACTRL_FIXPLL_CTRL0,
+		.bit_idx = 20,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "fixed_pll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fixed_pll_dco.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is fclk_div2/3/4's parent,
+		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
+		 * It is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+static const struct pll_mult_range a1_hifi_pll_mult_range = {
+	.min = 32,
+	.max = 64,
+};
+
+static const struct reg_sequence a1_hifi_init_regs[] = {
+	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
+};
+
+static struct clk_regmap a1_hifi_pll = {
+	.data = &(struct meson_clk_pll_data){
+		.en = {
+			.reg_off = ANACTRL_HIFIPLL_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.m = {
+			.reg_off = ANACTRL_HIFIPLL_CTRL0,
+			.shift   = 0,
+			.width   = 8,
+		},
+		.n = {
+			.reg_off = ANACTRL_HIFIPLL_CTRL0,
+			.shift   = 10,
+			.width   = 5,
+		},
+		.frac = {
+			.reg_off = ANACTRL_HIFIPLL_CTRL1,
+			.shift   = 0,
+			.width   = 19,
+		},
+		.l = {
+			.reg_off = ANACTRL_HIFIPLL_STS,
+			.shift   = 31,
+			.width   = 1,
+		},
+		.range = &a1_hifi_pll_mult_range,
+		.init_regs = a1_hifi_init_regs,
+		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
+		.strict_sequence = true,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hifi_pll",
+		.ops = &meson_clk_pll_ops,
+		.parent_data = &(const struct clk_parent_data){
+			.fw_name = "xtal_fixpll",
+			.name = "xtal_fixpll",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor a1_fclk_div2_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div2_div",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fixed_pll.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div2 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANACTRL_FIXPLL_CTRL0,
+		.bit_idx = 21,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div2",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by DDR clock in BL2 firmware
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+static struct clk_fixed_factor a1_fclk_div3_div = {
+	.mult = 1,
+	.div = 3,
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div3_div",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fixed_pll.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div3 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANACTRL_FIXPLL_CTRL0,
+		.bit_idx = 22,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div3",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div3_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by APB bus which setted in Romcode
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+static struct clk_fixed_factor a1_fclk_div5_div = {
+	.mult = 1,
+	.div = 5,
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div5_div",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fixed_pll.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div5 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANACTRL_FIXPLL_CTRL0,
+		.bit_idx = 23,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div5",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div5_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by AXI bus which setted in Romcode
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+static struct clk_fixed_factor a1_fclk_div7_div = {
+	.mult = 1,
+	.div = 7,
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div7_div",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fixed_pll.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div7 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = ANACTRL_FIXPLL_CTRL0,
+		.bit_idx = 24,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div7",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div7_div.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
+	.hws = {
+		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
+		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
+		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
+		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
+		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
+		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
+		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
+		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
+		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
+		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
+		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
+		[NR_PLL_CLKS]			= NULL,
+	},
+	.num = NR_PLL_CLKS,
+};
+
+static struct clk_regmap *const a1_pll_regmaps[] = {
+	&a1_fixed_pll_dco,
+	&a1_fixed_pll,
+	&a1_hifi_pll,
+	&a1_fclk_div2,
+	&a1_fclk_div3,
+	&a1_fclk_div5,
+	&a1_fclk_div7,
+};
+
+static int meson_a1_pll_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = meson_eeclkc_probe(pdev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct meson_eeclkc_data a1_pll_data = {
+		.regmap_clks = a1_pll_regmaps,
+		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
+		.hw_onecell_data = &a1_pll_hw_onecell_data,
+};
+static const struct of_device_id clkc_match_table[] = {
+	{
+		.compatible = "amlogic,a1-pll-clkc",
+		.data = &a1_pll_data
+	},
+	{ /* sentinel */ }
+};
+
+static struct platform_driver a1_driver = {
+	.probe		= meson_a1_pll_probe,
+	.driver		= {
+		.name	= "a1-pll-clkc",
+		.of_match_table = clkc_match_table,
+	},
+};
+
+builtin_platform_driver(a1_driver);
diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
new file mode 100644
index 0000000..99ee2a9
--- /dev/null
+++ b/drivers/clk/meson/a1-pll.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __A1_PLL_H
+#define __A1_PLL_H
+
+/* PLL register offset */
+#define ANACTRL_FIXPLL_CTRL0		0x80
+#define ANACTRL_FIXPLL_CTRL1		0x84
+#define ANACTRL_FIXPLL_CTRL2		0x88
+#define ANACTRL_FIXPLL_CTRL3		0x8c
+#define ANACTRL_FIXPLL_CTRL4		0x90
+#define ANACTRL_FIXPLL_STS		0x94
+#define ANACTRL_SYSPLL_CTRL0		0x100
+#define ANACTRL_SYSPLL_CTRL1		0x104
+#define ANACTRL_SYSPLL_CTRL2		0x108
+#define ANACTRL_SYSPLL_CTRL3		0x10c
+#define ANACTRL_SYSPLL_CTRL4		0x110
+#define ANACTRL_SYSPLL_STS		0x114
+#define ANACTRL_HIFIPLL_CTRL0		0x140
+#define ANACTRL_HIFIPLL_CTRL1		0x144
+#define ANACTRL_HIFIPLL_CTRL2		0x148
+#define ANACTRL_HIFIPLL_CTRL3		0x14c
+#define ANACTRL_HIFIPLL_CTRL4		0x150
+#define ANACTRL_HIFIPLL_STS		0x154
+#define ANACTRL_AUDDDS_CTRL0		0x180
+#define ANACTRL_AUDDDS_CTRL1		0x184
+#define ANACTRL_AUDDDS_CTRL2		0x188
+#define ANACTRL_AUDDDS_CTRL3		0x18c
+#define ANACTRL_AUDDDS_CTRL4		0x190
+#define ANACTRL_AUDDDS_STS		0x194
+#define ANACTRL_MISCTOP_CTRL0		0x1c0
+#define ANACTRL_POR_CNTL		0x208
+
+/*
+ * CLKID index values
+ *
+ * These indices are entirely contrived and do not map onto the hardware.
+ * It has now been decided to expose everything by default in the DT header:
+ * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
+ * to expose, such as the internal muxes and dividers of composite clocks,
+ * will remain defined here.
+ */
+#define CLKID_FIXED_PLL_DCO		0
+#define CLKID_FCLK_DIV2_DIV		2
+#define CLKID_FCLK_DIV3_DIV		3
+#define CLKID_FCLK_DIV5_DIV		4
+#define CLKID_FCLK_DIV7_DIV		5
+#define NR_PLL_CLKS			11
+
+/* include the CLKIDs that have been made part of the DT binding */
+#include <dt-bindings/clock/a1-pll-clkc.h>
+
+#endif /* __A1_PLL_H */
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
new file mode 100644
index 0000000..86a4733
--- /dev/null
+++ b/drivers/clk/meson/a1.c
@@ -0,0 +1,2264 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ */
+
+#include <linux/platform_device.h>
+#include "clk-pll.h"
+#include "clk-dualdiv.h"
+#include "meson-eeclk.h"
+#include "a1.h"
+
+/* PLLs clock in gates, its parent is xtal */
+static struct clk_regmap a1_xtal_clktree = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_clktree",
+		.ops = &clk_regmap_gate_ro_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+		/*
+		 * switch for xtal clock
+		 * Linux should not change it at runtime
+		 */
+	},
+};
+
+static struct clk_regmap a1_xtal_fixpll = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_fixpll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+		.flags = CLK_IS_CRITICAL,
+		/*
+		 * it feeds DDR,AXI,APB bus
+		 * Linux should not change it at runtime
+		 */
+	},
+};
+
+static struct clk_regmap a1_xtal_usb_phy = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 2,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_usb_phy",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_xtal_usb_ctrl = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 3,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_usb_ctrl",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_xtal_hifipll = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 4,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_hifipll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_xtal_syspll = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 5,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_syspll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_xtal_dds = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_OSCIN_CTRL,
+		.bit_idx = 6,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "xtal_dds",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct clk_parent_data sys_clk_parents[] = {
+	{ .fw_name = "xtal" },
+	{ .fw_name = "fclk_div2"},
+	{ .fw_name = "fclk_div3"},
+	{ .fw_name = "fclk_div5"},
+};
+
+static struct clk_regmap a1_sys_b_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SYS_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 26,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_b_sel",
+		.ops = &clk_regmap_mux_ro_ops,
+		.parent_data = sys_clk_parents,
+		.num_parents = ARRAY_SIZE(sys_clk_parents),
+	},
+};
+
+static struct clk_regmap a1_sys_b_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SYS_CLK_CTRL0,
+		.shift = 16,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_b_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sys_b_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_sys_b = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_CLK_CTRL0,
+		.bit_idx = 29,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "sys_b",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sys_b_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by APB bus which setted in Romcode
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+	},
+};
+
+static struct clk_regmap a1_sys_a_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SYS_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_a_sel",
+		.ops = &clk_regmap_mux_ro_ops,
+		.parent_data = sys_clk_parents,
+		.num_parents = ARRAY_SIZE(sys_clk_parents),
+	},
+};
+
+static struct clk_regmap a1_sys_a_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SYS_CLK_CTRL0,
+		.shift = 0,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_a_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sys_a_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_sys_a = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SYS_CLK_CTRL0,
+		.bit_idx = 13,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "sys_a",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sys_a_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by APB bus which setted in Romcode
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+	},
+};
+
+static struct clk_regmap a1_sys_clk = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SYS_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 31,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_clk",
+		.ops = &clk_regmap_mux_ro_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sys_a.hw, &a1_sys_b.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* rtc 32k clock in */
+static struct clk_regmap a1_rtc_32k_clkin = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_32k_clkin",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static const struct meson_clk_dualdiv_param a1_32k_div_table[] = {
+	{
+		.dual		= 1,
+		.n1		= 733,
+		.m1		= 8,
+		.n2		= 732,
+		.m2		= 11,
+	}, {}
+};
+
+static struct clk_regmap a1_rtc_32k_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = RTC_BY_OSCIN_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = RTC_BY_OSCIN_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = a1_32k_div_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_32k_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_rtc_32k_clkin.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_rtc_32k_xtal = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL1,
+		.bit_idx = 24,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "rtc_32k_xtal",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_rtc_32k_clkin.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static u32 rtc_32k_sel[] = { 0, 1 };
+
+static struct clk_regmap a1_rtc_32k_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = RTC_CTRL,
+		.mask = 0x3,
+		.shift = 0,
+		.table = rtc_32k_sel,
+		.flags = CLK_MUX_ROUND_CLOSEST,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_32k_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_rtc_32k_xtal.hw,
+			&a1_rtc_32k_div.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+struct clk_regmap a1_rtc_clk = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = RTC_BY_OSCIN_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "rtc_clk",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_rtc_32k_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* dsp a clk */
+static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
+static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .fw_name = "fclk_div2", },
+	{ .fw_name = "fclk_div3", },
+	{ .fw_name = "fclk_div5", },
+	{ .fw_name = "hifi_pll", },
+	{ .hw = &a1_rtc_clk.hw },
+};
+
+static struct clk_regmap a1_dspa_a_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPA_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 10,
+		.table = mux_table_dsp_ab,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa_a_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = dsp_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
+	},
+};
+
+static struct clk_regmap a1_dspa_a_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = DSPA_CLK_CTRL0,
+		.shift = 0,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa_a_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_a_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspa_a = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPA_CLK_CTRL0,
+		.bit_idx = 13,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspa_a",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_a_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspa_b_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPA_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 26,
+		.table = mux_table_dsp_ab,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa_b_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = dsp_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
+	},
+};
+
+static struct clk_regmap a1_dspa_b_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = DSPA_CLK_CTRL0,
+		.shift = 16,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa_b_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_b_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspa_b = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPA_CLK_CTRL0,
+		.bit_idx = 29,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspa_b",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_b_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspa_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPA_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspa_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_dspa_a.hw },
+			{ .hw = &a1_dspa_b.hw },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspa_en_dspa = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPA_CLK_EN,
+		.bit_idx = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspa_en_dspa",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap a1_dspa_en_nic = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPA_CLK_EN,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspa_en_nic",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspa_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* dsp b clk */
+static struct clk_regmap a1_dspb_a_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPB_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 10,
+		.table = mux_table_dsp_ab,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb_a_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = dsp_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
+	},
+};
+
+static struct clk_regmap a1_dspb_a_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = DSPB_CLK_CTRL0,
+		.shift = 0,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb_a_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_a_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspb_a = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPB_CLK_CTRL0,
+		.bit_idx = 13,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspb_a",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_a_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap a1_dspb_b_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPB_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 26,
+		.table = mux_table_dsp_ab,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb_b_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = dsp_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
+	},
+};
+
+static struct clk_regmap a1_dspb_b_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = DSPB_CLK_CTRL0,
+		.shift = 16,
+		.width = 10,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb_b_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_b_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspb_b = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPB_CLK_CTRL0,
+		.bit_idx = 29,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspb_b",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_b_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap a1_dspb_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DSPB_CLK_CTRL0,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dspb_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_a.hw, &a1_dspb_b.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dspb_en_dspb = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPB_CLK_EN,
+		.bit_idx = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspb_en_dspb",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_regmap a1_dspb_en_nic = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DSPB_CLK_EN,
+		.bit_idx = 0,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dspb_en_nic",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dspb_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* 12M/24M clock */
+static struct clk_regmap a1_24m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 11,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "24m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_fixed_factor a1_24m_div2 = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "24m_div2",
+		.ops = &clk_fixed_factor_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_24m.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_12m = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "12m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_24m_div2.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div2_divn_pre = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = CLK12_24_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div2_divn_pre",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fclk_div2",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_fclk_div2_divn = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CLK12_24_CTRL,
+		.bit_idx = 12,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "fclk_div2_divn",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2_divn_pre.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* gen clk */
+/*
+ * the second parent is sys_pll_div16, it will complete in the CPU clock,
+ * the forth parent is the clock measurement source, it relies on
+ * the clock measurement register configuration.
+ */
+static u32 gen_clk_table[] = { 0, 1, 3, 5, 6, 7, 8 };
+static const struct clk_parent_data gen_clk_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_rtc_clk.hw },
+	{ .fw_name = "hifi_pll", },
+	{ .fw_name = "fclk_div2", },
+	{ .fw_name = "fclk_div3", },
+	{ .fw_name = "fclk_div5", },
+	{ .fw_name = "fclk_div7", },
+};
+
+static struct clk_regmap a1_gen_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = GEN_CLK_CTRL,
+		.mask = 0xf,
+		.shift = 12,
+		.table = gen_clk_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gen_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = gen_clk_parent_data,
+		.num_parents = ARRAY_SIZE(gen_clk_parent_data),
+	},
+};
+
+static struct clk_regmap a1_gen_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = GEN_CLK_CTRL,
+		.shift = 0,
+		.width = 11,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "gen_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_gen_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_gen = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = GEN_CLK_CTRL,
+		.bit_idx = 11,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "gen",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_gen_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_saradc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SAR_ADC_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "saradc_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "xtal", },
+			{ .hw = &a1_sys_clk.hw, },
+		},
+		.num_parents = 2,
+	},
+};
+
+static struct clk_regmap a1_saradc_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SAR_ADC_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "saradc_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_saradc_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_saradc_clk = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SAR_ADC_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "saradc_clk",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_saradc_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* pwm a/b/c/d parent data */
+static const struct clk_parent_data pwm_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_sys_clk.hw },
+};
+
+/* pwm a clk */
+static struct clk_regmap a1_pwm_a_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.mask = 0x1,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_a_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_a_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_a_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_a_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_a = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_a",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_a_div.hw
+		},
+		.num_parents = 1,
+		/*
+		 * The CPU working voltage is controlled by pwm_a
+		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
+		 * to avoid changing at runtime.
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* pwm b clk */
+static struct clk_regmap a1_pwm_b_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.mask = 0x1,
+		.shift = 25,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_b_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_b_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.shift = 16,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_b_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_b_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_b = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_AB_CTRL,
+		.bit_idx = 24,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_b",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_b_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* pwm c clk */
+static struct clk_regmap a1_pwm_c_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.mask = 0x1,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_c_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_c_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_c_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_c_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_c = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_c",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_c_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* pwm d clk */
+static struct clk_regmap a1_pwm_d_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.mask = 0x1,
+		.shift = 25,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_d_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_d_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.shift = 16,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_d_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_d_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_d = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_CD_CTRL,
+		.bit_idx = 24,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_d",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_d_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data pwm_ef_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_sys_clk.hw },
+	{ .fw_name = "fclk_div5", },
+	{ .hw = &a1_rtc_clk.hw },
+};
+
+/* pwm e clk */
+static struct clk_regmap a1_pwm_e_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_e_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_ef_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_e_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_e_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_e_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_e = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_e",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_e_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* pwm f clk */
+static struct clk_regmap a1_pwm_f_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.mask = 0x3,
+		.shift = 25,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_f_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = pwm_ef_parent_data,
+		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
+	},
+};
+
+static struct clk_regmap a1_pwm_f_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.shift = 16,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "pwm_f_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_f_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_pwm_f = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PWM_CLK_EF_CTRL,
+		.bit_idx = 24,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "pwm_f",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_pwm_f_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* spicc clk */
+
+/*    div2   |\         |\       _____
+ *  ---------| |---DIV--| |     |     |    spicc out
+ *  ---------| |        | |-----|GATE |---------
+ *     ..... |/         | /     |_____|
+ *  --------------------|/
+ *                 24M
+ */
+static const struct clk_parent_data spicc_parents[] = {
+	{ .fw_name = "fclk_div2"},
+	{ .fw_name = "fclk_div3"},
+	{ .fw_name = "fclk_div5"},
+	{ .fw_name = "hifi_pll" },
+};
+
+static struct clk_regmap a1_spicc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SPICC_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spicc_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = spicc_parents,
+		.num_parents = 4,
+	},
+};
+
+static struct clk_regmap a1_spicc_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SPICC_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spicc_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_spicc_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_spicc_sel2 = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SPICC_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spicc_sel2",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_spicc_div.hw },
+			{ .fw_name = "xtal", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_spicc = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SPICC_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "spicc",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_spicc_sel2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* ts clk */
+static struct clk_regmap a1_ts_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = TS_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ts_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_ts = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = TS_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "ts",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_ts_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* spifc clk */
+static struct clk_regmap a1_spifc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SPIFC_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spifc_sel",
+		.ops = &clk_regmap_mux_ops,
+		/* the same parent with spicc */
+		.parent_data = spicc_parents,
+		.num_parents = 4,
+	},
+};
+
+static struct clk_regmap a1_spifc_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SPIFC_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spifc_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_spifc_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_spifc_sel2 = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SPIFC_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "spifc_sel2",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_spifc_div.hw },
+			{ .fw_name = "xtal", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_spifc = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SPIFC_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "spifc",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_spifc_sel2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* usb bus clk */
+static const struct clk_parent_data usb_bus_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_sys_clk.hw },
+	{ .fw_name = "fclk_div3", },
+	{ .fw_name = "fclk_div5", },
+};
+
+static struct clk_regmap a1_usb_bus_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = USB_BUSCLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "usb_bus_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = usb_bus_parent_data,
+		.num_parents = ARRAY_SIZE(usb_bus_parent_data),
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_usb_bus_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = USB_BUSCLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "usb_bus_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_usb_bus_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_usb_bus = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = USB_BUSCLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "usb_bus",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_usb_bus_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* sd emmc clk */
+static const struct clk_parent_data sd_emmc_parents[] = {
+	{ .fw_name = "fclk_div2", },
+	{ .fw_name = "fclk_div3", },
+	{ .fw_name = "fclk_div5", },
+	{ .fw_name = "hifi_pll", },
+};
+
+static struct clk_regmap a1_sd_emmc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SD_EMMC_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sd_emmc_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = sd_emmc_parents,
+		.num_parents = 4,
+	},
+};
+
+static struct clk_regmap a1_sd_emmc_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = SD_EMMC_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sd_emmc_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sd_emmc_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_sd_emmc_sel2 = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SD_EMMC_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sd_emmc_sel2",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_sd_emmc_div.hw },
+			{ .fw_name = "xtal", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_sd_emmc = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = SD_EMMC_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "sd_emmc",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_sd_emmc_sel2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_psram_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PSRAM_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "psram_sel",
+		.ops = &clk_regmap_mux_ops,
+		/* the same parent with sd_emmc */
+		.parent_data = sd_emmc_parents,
+		.num_parents = 4,
+	},
+};
+
+static struct clk_regmap a1_psram_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = PSRAM_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "psram_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_psram_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_psram_sel2 = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = PSRAM_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "psram_sel2",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_psram_div.hw },
+			{ .fw_name = "xtal", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_psram = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = PSRAM_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "psram",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_psram_sel2.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* dmc clk */
+static struct clk_regmap a1_dmc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DMC_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dmc_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = sd_emmc_parents,
+		.num_parents = 4,
+	},
+};
+
+static struct clk_regmap a1_dmc_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = DMC_CLK_CTRL,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dmc_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dmc_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dmc_sel2 = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = DMC_CLK_CTRL,
+		.mask = 0x1,
+		.shift = 15,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "dmc_sel2",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a1_dmc_div.hw },
+			{ .fw_name = "xtal", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_dmc = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = DMC_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "dmc",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_dmc_sel2.hw
+		},
+		.num_parents = 1,
+		/*
+		 * This clock is used by DDR clock which setted in BL2
+		 * and is required by the platform to operate correctly.
+		 * Until the following condition are met, we need this clock to
+		 * be marked as critical:
+		 * a) Mark the clock used by a firmware resource, if possible
+		 * b) CCF has a clock hand-off mechanism to make the sure the
+		 *    clock stays on until the proper driver comes along
+		 */
+		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+	},
+};
+
+/* cec A clock */
+static struct clk_regmap a1_ceca_32k_clkin = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CLK_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "ceca_32k_clkin",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_ceca_32k_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECA_CLK_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECA_CLK_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECA_CLK_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECA_CLK_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECA_CLK_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = a1_32k_div_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_32k_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_ceca_32k_clkin.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_ceca_32k_sel_pre = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CLK_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+		.flags = CLK_MUX_ROUND_CLOSEST,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_32k_sel_pre",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_ceca_32k_div.hw,
+			&a1_ceca_32k_clkin.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_ceca_32k_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECA_CLK_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+		.flags = CLK_MUX_ROUND_CLOSEST,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_32k_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_ceca_32k_sel_pre.hw,
+			&a1_rtc_clk.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_ceca_32k_clkout = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECA_CLK_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ceca_32k_clkout",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_ceca_32k_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* cec B clock */
+static struct clk_regmap a1_cecb_32k_clkin = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CLK_CTRL0,
+		.bit_idx = 31,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "cecb_32k_clkin",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_cecb_32k_div = {
+	.data = &(struct meson_clk_dualdiv_data){
+		.n1 = {
+			.reg_off = CECB_CLK_CTRL0,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.n2 = {
+			.reg_off = CECB_CLK_CTRL0,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.m1 = {
+			.reg_off = CECB_CLK_CTRL1,
+			.shift   = 0,
+			.width   = 12,
+		},
+		.m2 = {
+			.reg_off = CECB_CLK_CTRL1,
+			.shift   = 12,
+			.width   = 12,
+		},
+		.dual = {
+			.reg_off = CECB_CLK_CTRL0,
+			.shift   = 28,
+			.width   = 1,
+		},
+		.table = a1_32k_div_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_32k_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_cecb_32k_clkin.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a1_cecb_32k_sel_pre = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CLK_CTRL1,
+		.mask = 0x1,
+		.shift = 24,
+		.flags = CLK_MUX_ROUND_CLOSEST,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_32k_sel_pre",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_cecb_32k_div.hw,
+			&a1_cecb_32k_clkin.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_cecb_32k_sel = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = CECB_CLK_CTRL1,
+		.mask = 0x1,
+		.shift = 31,
+		.flags = CLK_MUX_ROUND_CLOSEST,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_32k_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_cecb_32k_sel_pre.hw,
+			&a1_rtc_clk.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a1_cecb_32k_clkout = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = CECB_CLK_CTRL0,
+		.bit_idx = 30,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "cecb_32k_clkout",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_cecb_32k_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+#define MESON_GATE(_name, _reg, _bit) \
+	MESON_PCLK(_name, _reg, _bit, &a1_sys_clk.hw)
+
+static MESON_GATE(a1_clk_tree,		SYS_CLK_EN0,	0);
+static MESON_GATE(a1_reset_ctrl,	SYS_CLK_EN0,	1);
+static MESON_GATE(a1_analog_ctrl,	SYS_CLK_EN0,	2);
+static MESON_GATE(a1_pwr_ctrl,		SYS_CLK_EN0,	3);
+static MESON_GATE(a1_pad_ctrl,		SYS_CLK_EN0,	4);
+static MESON_GATE(a1_sys_ctrl,		SYS_CLK_EN0,	5);
+static MESON_GATE(a1_temp_sensor,	SYS_CLK_EN0,	6);
+static MESON_GATE(a1_am2axi_dev,	SYS_CLK_EN0,	7);
+static MESON_GATE(a1_spicc_b,		SYS_CLK_EN0,	8);
+static MESON_GATE(a1_spicc_a,		SYS_CLK_EN0,	9);
+static MESON_GATE(a1_clk_msr,		SYS_CLK_EN0,	10);
+static MESON_GATE(a1_audio,		SYS_CLK_EN0,	11);
+static MESON_GATE(a1_jtag_ctrl,		SYS_CLK_EN0,	12);
+static MESON_GATE(a1_saradc,		SYS_CLK_EN0,	13);
+static MESON_GATE(a1_pwm_ef,		SYS_CLK_EN0,	14);
+static MESON_GATE(a1_pwm_cd,		SYS_CLK_EN0,	15);
+static MESON_GATE(a1_pwm_ab,		SYS_CLK_EN0,	16);
+static MESON_GATE(a1_cec,		SYS_CLK_EN0,	17);
+static MESON_GATE(a1_i2c_s,		SYS_CLK_EN0,	18);
+static MESON_GATE(a1_ir_ctrl,		SYS_CLK_EN0,	19);
+static MESON_GATE(a1_i2c_m_d,		SYS_CLK_EN0,	20);
+static MESON_GATE(a1_i2c_m_c,		SYS_CLK_EN0,	21);
+static MESON_GATE(a1_i2c_m_b,		SYS_CLK_EN0,	22);
+static MESON_GATE(a1_i2c_m_a,		SYS_CLK_EN0,	23);
+static MESON_GATE(a1_acodec,		SYS_CLK_EN0,	24);
+static MESON_GATE(a1_otp,		SYS_CLK_EN0,	25);
+static MESON_GATE(a1_sd_emmc_a,		SYS_CLK_EN0,	26);
+static MESON_GATE(a1_usb_phy,		SYS_CLK_EN0,	27);
+static MESON_GATE(a1_usb_ctrl,		SYS_CLK_EN0,	28);
+static MESON_GATE(a1_sys_dspb,		SYS_CLK_EN0,	29);
+static MESON_GATE(a1_sys_dspa,		SYS_CLK_EN0,	30);
+static MESON_GATE(a1_dma,		SYS_CLK_EN0,	31);
+static MESON_GATE(a1_irq_ctrl,		SYS_CLK_EN1,	0);
+static MESON_GATE(a1_nic,		SYS_CLK_EN1,	1);
+static MESON_GATE(a1_gic,		SYS_CLK_EN1,	2);
+static MESON_GATE(a1_uart_c,		SYS_CLK_EN1,	3);
+static MESON_GATE(a1_uart_b,		SYS_CLK_EN1,	4);
+static MESON_GATE(a1_uart_a,		SYS_CLK_EN1,	5);
+static MESON_GATE(a1_sys_psram,		SYS_CLK_EN1,	6);
+static MESON_GATE(a1_rsa,		SYS_CLK_EN1,	8);
+static MESON_GATE(a1_coresight,		SYS_CLK_EN1,	9);
+static MESON_GATE(a1_am2axi_vad,	AXI_CLK_EN,	0);
+static MESON_GATE(a1_audio_vad,		AXI_CLK_EN,	1);
+static MESON_GATE(a1_axi_dmc,		AXI_CLK_EN,	3);
+static MESON_GATE(a1_axi_psram,		AXI_CLK_EN,	4);
+static MESON_GATE(a1_ramb,		AXI_CLK_EN,	5);
+static MESON_GATE(a1_rama,		AXI_CLK_EN,	6);
+static MESON_GATE(a1_axi_spifc,		AXI_CLK_EN,	7);
+static MESON_GATE(a1_axi_nic,		AXI_CLK_EN,	8);
+static MESON_GATE(a1_axi_dma,		AXI_CLK_EN,	9);
+static MESON_GATE(a1_cpu_ctrl,		AXI_CLK_EN,	10);
+static MESON_GATE(a1_rom,		AXI_CLK_EN,	11);
+static MESON_GATE(a1_prod_i2c,		AXI_CLK_EN,	12);
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw_onecell_data a1_periphs_hw_onecell_data = {
+	.hws = {
+		[CLKID_SYS_B_SEL]		= &a1_sys_b_sel.hw,
+		[CLKID_SYS_B_DIV]		= &a1_sys_b_div.hw,
+		[CLKID_SYS_B]			= &a1_sys_b.hw,
+		[CLKID_SYS_A_SEL]		= &a1_sys_a_sel.hw,
+		[CLKID_SYS_A_DIV]		= &a1_sys_a_div.hw,
+		[CLKID_SYS_A]			= &a1_sys_a.hw,
+		[CLKID_SYS_CLK]			= &a1_sys_clk.hw,
+		[CLKID_XTAL_CLKTREE]		= &a1_xtal_clktree.hw,
+		[CLKID_XTAL_FIXPLL]		= &a1_xtal_fixpll.hw,
+		[CLKID_XTAL_USB_PHY]		= &a1_xtal_usb_phy.hw,
+		[CLKID_XTAL_USB_CTRL]		= &a1_xtal_usb_ctrl.hw,
+		[CLKID_XTAL_HIFIPLL]		= &a1_xtal_hifipll.hw,
+		[CLKID_XTAL_SYSPLL]		= &a1_xtal_syspll.hw,
+		[CLKID_XTAL_DDS]		= &a1_xtal_dds.hw,
+		[CLKID_CLKTREE]			= &a1_clk_tree.hw,
+		[CLKID_RESET_CTRL]		= &a1_reset_ctrl.hw,
+		[CLKID_ANALOG_CTRL]		= &a1_analog_ctrl.hw,
+		[CLKID_PWR_CTRL]		= &a1_pwr_ctrl.hw,
+		[CLKID_PAD_CTRL]		= &a1_pad_ctrl.hw,
+		[CLKID_SYS_CTRL]		= &a1_sys_ctrl.hw,
+		[CLKID_TEMP_SENSOR]		= &a1_temp_sensor.hw,
+		[CLKID_AM2AXI_DIV]		= &a1_am2axi_dev.hw,
+		[CLKID_SPICC_B]			= &a1_spicc_b.hw,
+		[CLKID_SPICC_A]			= &a1_spicc_a.hw,
+		[CLKID_CLK_MSR]			= &a1_clk_msr.hw,
+		[CLKID_AUDIO]			= &a1_audio.hw,
+		[CLKID_JTAG_CTRL]		= &a1_jtag_ctrl.hw,
+		[CLKID_SARADC]			= &a1_saradc.hw,
+		[CLKID_PWM_EF]			= &a1_pwm_ef.hw,
+		[CLKID_PWM_CD]			= &a1_pwm_cd.hw,
+		[CLKID_PWM_AB]			= &a1_pwm_ab.hw,
+		[CLKID_CEC]			= &a1_cec.hw,
+		[CLKID_I2C_S]			= &a1_i2c_s.hw,
+		[CLKID_IR_CTRL]			= &a1_ir_ctrl.hw,
+		[CLKID_I2C_M_D]			= &a1_i2c_m_d.hw,
+		[CLKID_I2C_M_C]			= &a1_i2c_m_c.hw,
+		[CLKID_I2C_M_B]			= &a1_i2c_m_b.hw,
+		[CLKID_I2C_M_A]			= &a1_i2c_m_a.hw,
+		[CLKID_ACODEC]			= &a1_acodec.hw,
+		[CLKID_OTP]			= &a1_otp.hw,
+		[CLKID_SD_EMMC_A]		= &a1_sd_emmc_a.hw,
+		[CLKID_USB_PHY]			= &a1_usb_phy.hw,
+		[CLKID_USB_CTRL]		= &a1_usb_ctrl.hw,
+		[CLKID_SYS_DSPB]		= &a1_sys_dspb.hw,
+		[CLKID_SYS_DSPA]		= &a1_sys_dspa.hw,
+		[CLKID_DMA]			= &a1_dma.hw,
+		[CLKID_IRQ_CTRL]		= &a1_irq_ctrl.hw,
+		[CLKID_NIC]			= &a1_nic.hw,
+		[CLKID_GIC]			= &a1_gic.hw,
+		[CLKID_UART_C]			= &a1_uart_c.hw,
+		[CLKID_UART_B]			= &a1_uart_b.hw,
+		[CLKID_UART_A]			= &a1_uart_a.hw,
+		[CLKID_SYS_PSRAM]		= &a1_sys_psram.hw,
+		[CLKID_RSA]			= &a1_rsa.hw,
+		[CLKID_CORESIGHT]		= &a1_coresight.hw,
+		[CLKID_AM2AXI_VAD]		= &a1_am2axi_vad.hw,
+		[CLKID_AUDIO_VAD]		= &a1_audio_vad.hw,
+		[CLKID_AXI_DMC]			= &a1_axi_dmc.hw,
+		[CLKID_AXI_PSRAM]		= &a1_axi_psram.hw,
+		[CLKID_RAMB]			= &a1_ramb.hw,
+		[CLKID_RAMA]			= &a1_rama.hw,
+		[CLKID_AXI_SPIFC]		= &a1_axi_spifc.hw,
+		[CLKID_AXI_NIC]			= &a1_axi_nic.hw,
+		[CLKID_AXI_DMA]			= &a1_axi_dma.hw,
+		[CLKID_CPU_CTRL]		= &a1_cpu_ctrl.hw,
+		[CLKID_ROM]			= &a1_rom.hw,
+		[CLKID_PROC_I2C]		= &a1_prod_i2c.hw,
+		[CLKID_DSPA_A_SEL]		= &a1_dspa_a_sel.hw,
+		[CLKID_DSPA_A_DIV]		= &a1_dspa_a_div.hw,
+		[CLKID_DSPA_A]			= &a1_dspa_a.hw,
+		[CLKID_DSPA_B_SEL]		= &a1_dspa_b_sel.hw,
+		[CLKID_DSPA_B_DIV]		= &a1_dspa_b_div.hw,
+		[CLKID_DSPA_B]			= &a1_dspa_b.hw,
+		[CLKID_DSPA_SEL]		= &a1_dspa_sel.hw,
+		[CLKID_DSPB_A_SEL]		= &a1_dspb_a_sel.hw,
+		[CLKID_DSPB_A_DIV]		= &a1_dspb_a_div.hw,
+		[CLKID_DSPB_A]			= &a1_dspb_a.hw,
+		[CLKID_DSPB_B_SEL]		= &a1_dspb_b_sel.hw,
+		[CLKID_DSPB_B_DIV]		= &a1_dspb_b_div.hw,
+		[CLKID_DSPB_B]			= &a1_dspb_b.hw,
+		[CLKID_DSPB_SEL]		= &a1_dspb_sel.hw,
+		[CLKID_DSPA_EN_DSPA]		= &a1_dspa_en_dspa.hw,
+		[CLKID_DSPA_EN_NIC]		= &a1_dspa_en_nic.hw,
+		[CLKID_DSPB_EN_DSPB]		= &a1_dspb_en_dspb.hw,
+		[CLKID_DSPB_EN_NIC]		= &a1_dspb_en_nic.hw,
+		[CLKID_24M]			= &a1_24m.hw,
+		[CLKID_24M_DIV2]		= &a1_24m_div2.hw,
+		[CLKID_12M]			= &a1_12m.hw,
+		[CLKID_DIV2_PRE]		= &a1_fclk_div2_divn_pre.hw,
+		[CLKID_FCLK_DIV2_DIVN]		= &a1_fclk_div2_divn.hw,
+		[CLKID_GEN_SEL]			= &a1_gen_sel.hw,
+		[CLKID_GEN_DIV]			= &a1_gen_div.hw,
+		[CLKID_GEN]			= &a1_gen.hw,
+		[CLKID_SARADC_SEL]		= &a1_saradc_sel.hw,
+		[CLKID_SARADC_DIV]		= &a1_saradc_div.hw,
+		[CLKID_SARADC_CLK]		= &a1_saradc_clk.hw,
+		[CLKID_PWM_A_SEL]		= &a1_pwm_a_sel.hw,
+		[CLKID_PWM_A_DIV]		= &a1_pwm_a_div.hw,
+		[CLKID_PWM_A]			= &a1_pwm_a.hw,
+		[CLKID_PWM_B_SEL]		= &a1_pwm_b_sel.hw,
+		[CLKID_PWM_B_DIV]		= &a1_pwm_b_div.hw,
+		[CLKID_PWM_B]			= &a1_pwm_b.hw,
+		[CLKID_PWM_C_SEL]		= &a1_pwm_c_sel.hw,
+		[CLKID_PWM_C_DIV]		= &a1_pwm_c_div.hw,
+		[CLKID_PWM_C]			= &a1_pwm_c.hw,
+		[CLKID_PWM_D_SEL]		= &a1_pwm_d_sel.hw,
+		[CLKID_PWM_D_DIV]		= &a1_pwm_d_div.hw,
+		[CLKID_PWM_D]			= &a1_pwm_d.hw,
+		[CLKID_PWM_E_SEL]		= &a1_pwm_e_sel.hw,
+		[CLKID_PWM_E_DIV]		= &a1_pwm_e_div.hw,
+		[CLKID_PWM_E]			= &a1_pwm_e.hw,
+		[CLKID_PWM_F_SEL]		= &a1_pwm_f_sel.hw,
+		[CLKID_PWM_F_DIV]		= &a1_pwm_f_div.hw,
+		[CLKID_PWM_F]			= &a1_pwm_f.hw,
+		[CLKID_SPICC_SEL]		= &a1_spicc_sel.hw,
+		[CLKID_SPICC_DIV]		= &a1_spicc_div.hw,
+		[CLKID_SPICC_SEL2]		= &a1_spicc_sel2.hw,
+		[CLKID_SPICC]			= &a1_spicc.hw,
+		[CLKID_TS_DIV]			= &a1_ts_div.hw,
+		[CLKID_TS]			= &a1_ts.hw,
+		[CLKID_SPIFC_SEL]		= &a1_spifc_sel.hw,
+		[CLKID_SPIFC_DIV]		= &a1_spifc_div.hw,
+		[CLKID_SPIFC_SEL2]		= &a1_spifc_sel2.hw,
+		[CLKID_SPIFC]			= &a1_spifc.hw,
+		[CLKID_USB_BUS_SEL]		= &a1_usb_bus_sel.hw,
+		[CLKID_USB_BUS_DIV]		= &a1_usb_bus_div.hw,
+		[CLKID_USB_BUS]			= &a1_usb_bus.hw,
+		[CLKID_SD_EMMC_SEL]		= &a1_sd_emmc_sel.hw,
+		[CLKID_SD_EMMC_DIV]		= &a1_sd_emmc_div.hw,
+		[CLKID_SD_EMMC_SEL2]		= &a1_sd_emmc_sel2.hw,
+		[CLKID_SD_EMMC]			= &a1_sd_emmc.hw,
+		[CLKID_PSRAM_SEL]		= &a1_psram_sel.hw,
+		[CLKID_PSRAM_DIV]		= &a1_psram_div.hw,
+		[CLKID_PSRAM_SEL2]		= &a1_psram_sel2.hw,
+		[CLKID_PSRAM]			= &a1_psram.hw,
+		[CLKID_DMC_SEL]			= &a1_dmc_sel.hw,
+		[CLKID_DMC_DIV]			= &a1_dmc_div.hw,
+		[CLKID_DMC_SEL2]		= &a1_dmc_sel2.hw,
+		[CLKID_DMC]			= &a1_dmc.hw,
+		[CLKID_RTC_32K_CLKIN]		= &a1_rtc_32k_clkin.hw,
+		[CLKID_RTC_32K_DIV]		= &a1_rtc_32k_div.hw,
+		[CLKID_RTC_32K_XTAL]		= &a1_rtc_32k_xtal.hw,
+		[CLKID_RTC_32K_SEL]		= &a1_rtc_32k_sel.hw,
+		[CLKID_RTC_CLK]			= &a1_rtc_clk.hw,
+		[CLKID_CECA_32K_CLKIN]		= &a1_ceca_32k_clkin.hw,
+		[CLKID_CECA_32K_DIV]		= &a1_ceca_32k_div.hw,
+		[CLKID_CECA_32K_SEL_PRE]	= &a1_ceca_32k_sel_pre.hw,
+		[CLKID_CECA_32K_SEL]		= &a1_ceca_32k_sel.hw,
+		[CLKID_CECA_32K]		= &a1_ceca_32k_clkout.hw,
+		[CLKID_CECB_32K_CLKIN]		= &a1_cecb_32k_clkin.hw,
+		[CLKID_CECB_32K_DIV]		= &a1_cecb_32k_div.hw,
+		[CLKID_CECB_32K_SEL_PRE]	= &a1_cecb_32k_sel_pre.hw,
+		[CLKID_CECB_32K_SEL]		= &a1_cecb_32k_sel.hw,
+		[CLKID_CECB_32K]		= &a1_cecb_32k_clkout.hw,
+		[NR_CLKS]			= NULL,
+	},
+	.num = NR_CLKS,
+};
+
+/* Convenience table to populate regmap in .probe */
+static struct clk_regmap *const a1_periphs_regmaps[] = {
+	&a1_xtal_clktree,
+	&a1_xtal_fixpll,
+	&a1_xtal_usb_phy,
+	&a1_xtal_usb_ctrl,
+	&a1_xtal_hifipll,
+	&a1_xtal_syspll,
+	&a1_xtal_dds,
+	&a1_clk_tree,
+	&a1_reset_ctrl,
+	&a1_analog_ctrl,
+	&a1_pwr_ctrl,
+	&a1_sys_ctrl,
+	&a1_temp_sensor,
+	&a1_am2axi_dev,
+	&a1_spicc_b,
+	&a1_spicc_a,
+	&a1_clk_msr,
+	&a1_audio,
+	&a1_jtag_ctrl,
+	&a1_saradc,
+	&a1_pwm_ef,
+	&a1_pwm_cd,
+	&a1_pwm_ab,
+	&a1_cec,
+	&a1_i2c_s,
+	&a1_ir_ctrl,
+	&a1_i2c_m_d,
+	&a1_i2c_m_c,
+	&a1_i2c_m_b,
+	&a1_i2c_m_a,
+	&a1_acodec,
+	&a1_otp,
+	&a1_sd_emmc_a,
+	&a1_usb_phy,
+	&a1_usb_ctrl,
+	&a1_sys_dspb,
+	&a1_sys_dspa,
+	&a1_dma,
+	&a1_irq_ctrl,
+	&a1_nic,
+	&a1_gic,
+	&a1_uart_c,
+	&a1_uart_b,
+	&a1_uart_a,
+	&a1_sys_psram,
+	&a1_rsa,
+	&a1_coresight,
+	&a1_am2axi_vad,
+	&a1_audio_vad,
+	&a1_axi_dmc,
+	&a1_axi_psram,
+	&a1_ramb,
+	&a1_rama,
+	&a1_axi_spifc,
+	&a1_axi_nic,
+	&a1_axi_dma,
+	&a1_cpu_ctrl,
+	&a1_rom,
+	&a1_prod_i2c,
+	&a1_dspa_a_sel,
+	&a1_dspa_a_div,
+	&a1_dspa_a,
+	&a1_dspa_b_sel,
+	&a1_dspa_b_div,
+	&a1_dspa_b,
+	&a1_dspa_sel,
+	&a1_dspb_a_sel,
+	&a1_dspb_a_div,
+	&a1_dspb_a,
+	&a1_dspb_b_sel,
+	&a1_dspb_b_div,
+	&a1_dspb_b,
+	&a1_dspb_sel,
+	&a1_dspa_en_dspa,
+	&a1_dspa_en_nic,
+	&a1_dspb_en_dspb,
+	&a1_dspb_en_nic,
+	&a1_24m,
+	&a1_12m,
+	&a1_fclk_div2_divn_pre,
+	&a1_fclk_div2_divn,
+	&a1_gen_sel,
+	&a1_gen_div,
+	&a1_gen,
+	&a1_saradc_sel,
+	&a1_saradc_div,
+	&a1_saradc_clk,
+	&a1_pwm_a_sel,
+	&a1_pwm_a_div,
+	&a1_pwm_a,
+	&a1_pwm_b_sel,
+	&a1_pwm_b_div,
+	&a1_pwm_b,
+	&a1_pwm_c_sel,
+	&a1_pwm_c_div,
+	&a1_pwm_c,
+	&a1_pwm_d_sel,
+	&a1_pwm_d_div,
+	&a1_pwm_d,
+	&a1_pwm_e_sel,
+	&a1_pwm_e_div,
+	&a1_pwm_e,
+	&a1_pwm_f_sel,
+	&a1_pwm_f_div,
+	&a1_pwm_f,
+	&a1_spicc_sel,
+	&a1_spicc_div,
+	&a1_spicc_sel2,
+	&a1_spicc,
+	&a1_ts_div,
+	&a1_ts,
+	&a1_spifc_sel,
+	&a1_spifc_div,
+	&a1_spifc_sel2,
+	&a1_spifc,
+	&a1_usb_bus_sel,
+	&a1_usb_bus_div,
+	&a1_usb_bus,
+	&a1_sd_emmc_sel,
+	&a1_sd_emmc_div,
+	&a1_sd_emmc_sel2,
+	&a1_sd_emmc,
+	&a1_psram_sel,
+	&a1_psram_div,
+	&a1_psram_sel2,
+	&a1_psram,
+	&a1_dmc_sel,
+	&a1_dmc_div,
+	&a1_dmc_sel2,
+	&a1_dmc,
+	&a1_sys_b_sel,
+	&a1_sys_b_div,
+	&a1_sys_b,
+	&a1_sys_a_sel,
+	&a1_sys_a_div,
+	&a1_sys_a,
+	&a1_sys_clk,
+	&a1_rtc_32k_clkin,
+	&a1_rtc_32k_div,
+	&a1_rtc_32k_xtal,
+	&a1_rtc_32k_sel,
+	&a1_rtc_clk,
+	&a1_ceca_32k_clkin,
+	&a1_ceca_32k_div,
+	&a1_ceca_32k_sel_pre,
+	&a1_ceca_32k_sel,
+	&a1_ceca_32k_clkout,
+	&a1_cecb_32k_clkin,
+	&a1_cecb_32k_div,
+	&a1_cecb_32k_sel_pre,
+	&a1_cecb_32k_sel,
+	&a1_cecb_32k_clkout,
+};
+
+static int meson_a1_periphs_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = meson_eeclkc_probe(pdev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct meson_eeclkc_data a1_periphs_data = {
+		.regmap_clks = a1_periphs_regmaps,
+		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
+		.hw_onecell_data = &a1_periphs_hw_onecell_data,
+};
+static const struct of_device_id clkc_match_table[] = {
+	{
+		.compatible = "amlogic,a1-periphs-clkc",
+		.data = &a1_periphs_data
+	},
+	{ /* sentinel */ }
+};
+
+static struct platform_driver a1_driver = {
+	.probe		= meson_a1_periphs_probe,
+	.driver		= {
+		.name	= "a1-periphs-clkc",
+		.of_match_table = clkc_match_table,
+	},
+};
+
+builtin_platform_driver(a1_driver);
diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
new file mode 100644
index 0000000..1ae5e04
--- /dev/null
+++ b/drivers/clk/meson/a1.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __A1_H
+#define __A1_H
+
+/* peripheral clock controller register offset */
+#define SYS_OSCIN_CTRL			0x0
+#define RTC_BY_OSCIN_CTRL0		0x4
+#define RTC_BY_OSCIN_CTRL1		0x8
+#define RTC_CTRL			0xc
+#define SYS_CLK_CTRL0			0x10
+#define AXI_CLK_CTRL0			0x14
+#define SYS_CLK_EN0			0x1c
+#define SYS_CLK_EN1			0x20
+#define AXI_CLK_EN			0x24
+#define DSPA_CLK_EN			0x28
+#define DSPB_CLK_EN			0x2c
+#define DSPA_CLK_CTRL0			0x30
+#define DSPB_CLK_CTRL0			0x34
+#define CLK12_24_CTRL			0x38
+#define GEN_CLK_CTRL			0x3c
+#define TIMESTAMP_CTRL0			0x40
+#define TIMESTAMP_CTRL1			0x44
+#define TIMESTAMP_CTRL2			0x48
+#define TIMESTAMP_VAL0			0x4c
+#define TIMESTAMP_VAL1			0x50
+#define TIMEBASE_CTRL0			0x54
+#define TIMEBASE_CTRL1			0x58
+#define SAR_ADC_CLK_CTRL		0xc0
+#define PWM_CLK_AB_CTRL			0xc4
+#define PWM_CLK_CD_CTRL			0xc8
+#define PWM_CLK_EF_CTRL			0xcc
+#define SPICC_CLK_CTRL			0xd0
+#define TS_CLK_CTRL			0xd4
+#define SPIFC_CLK_CTRL			0xd8
+#define USB_BUSCLK_CTRL			0xdc
+#define SD_EMMC_CLK_CTRL		0xe0
+#define CECA_CLK_CTRL0			0xe4
+#define CECA_CLK_CTRL1			0xe8
+#define CECB_CLK_CTRL0			0xec
+#define CECB_CLK_CTRL1			0xf0
+#define PSRAM_CLK_CTRL			0xf4
+#define DMC_CLK_CTRL			0xf8
+#define FCLK_DIV1_SEL			0xfc
+#define TST_CTRL			0x100
+
+#define CLKID_XTAL_CLKTREE		0
+#define CLKID_SYS_A_SEL			89
+#define CLKID_SYS_A_DIV			90
+#define CLKID_SYS_A			91
+#define CLKID_SYS_B_SEL			92
+#define CLKID_SYS_B_DIV			93
+#define CLKID_SYS_B			94
+#define CLKID_DSPA_A_SEL		95
+#define CLKID_DSPA_A_DIV		96
+#define CLKID_DSPA_A			97
+#define CLKID_DSPA_B_SEL		98
+#define CLKID_DSPA_B_DIV		99
+#define CLKID_DSPA_B			100
+#define CLKID_DSPB_A_SEL		101
+#define CLKID_DSPB_A_DIV		102
+#define CLKID_DSPB_A			103
+#define CLKID_DSPB_B_SEL		104
+#define CLKID_DSPB_B_DIV		105
+#define CLKID_DSPB_B			106
+#define CLKID_RTC_32K_CLKIN		107
+#define CLKID_RTC_32K_DIV		108
+#define CLKID_RTC_32K_XTAL		109
+#define CLKID_RTC_32K_SEL		110
+#define CLKID_CECB_32K_CLKIN		111
+#define CLKID_CECB_32K_DIV		112
+#define CLKID_CECB_32K_SEL_PRE		113
+#define CLKID_CECB_32K_SEL		114
+#define CLKID_CECA_32K_CLKIN		115
+#define CLKID_CECA_32K_DIV		116
+#define CLKID_CECA_32K_SEL_PRE		117
+#define CLKID_CECA_32K_SEL		118
+#define CLKID_DIV2_PRE			119
+#define CLKID_24M_DIV2			120
+#define CLKID_GEN_SEL			121
+#define CLKID_GEN_DIV			122
+#define CLKID_SARADC_DIV		123
+#define CLKID_PWM_A_SEL			124
+#define CLKID_PWM_A_DIV			125
+#define CLKID_PWM_B_SEL			126
+#define CLKID_PWM_B_DIV			127
+#define CLKID_PWM_C_SEL			128
+#define CLKID_PWM_C_DIV			129
+#define CLKID_PWM_D_SEL			130
+#define CLKID_PWM_D_DIV			131
+#define CLKID_PWM_E_SEL			132
+#define CLKID_PWM_E_DIV			133
+#define CLKID_PWM_F_SEL			134
+#define CLKID_PWM_F_DIV			135
+#define CLKID_SPICC_SEL			136
+#define CLKID_SPICC_DIV			137
+#define CLKID_SPICC_SEL2		138
+#define CLKID_TS_DIV			139
+#define CLKID_SPIFC_SEL			140
+#define CLKID_SPIFC_DIV			141
+#define CLKID_SPIFC_SEL2		142
+#define CLKID_USB_BUS_SEL		143
+#define CLKID_USB_BUS_DIV		144
+#define CLKID_SD_EMMC_SEL		145
+#define CLKID_SD_EMMC_DIV		146
+#define CLKID_SD_EMMC_SEL2		147
+#define CLKID_PSRAM_SEL			148
+#define CLKID_PSRAM_DIV			149
+#define CLKID_PSRAM_SEL2		150
+#define CLKID_DMC_SEL			151
+#define CLKID_DMC_DIV			152
+#define CLKID_DMC_SEL2			153
+#define NR_CLKS				154
+
+#include <dt-bindings/clock/a1-clkc.h>
+
+#endif /* __A1_H */
-- 
1.9.1


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

* Re: [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-10-18  7:14 ` [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
@ 2019-10-21 10:43   ` Jerome Brunet
  2019-10-22  5:30     ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-10-21 10:43 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree


On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:

> Add the documentation to support Amlogic A1 clock driver,
> and add A1 clock controller bindings.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
>  .../devicetree/bindings/clock/amlogic,a1-clkc.yaml | 143
> +++++++++++++++++++++

Those are 2 different controllers, not variants.
One description (one file) per controller please

>  include/dt-bindings/clock/a1-clkc.h                |  98 ++++++++++++++
>  include/dt-bindings/clock/a1-pll-clkc.h            |  16 +++
>  3 files changed, 257 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/a1-clkc.h
>  create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> new file mode 100644
> index 0000000..b382eebe
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> @@ -0,0 +1,143 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/clock/amlogic,a1-clkc.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Amlogic Meson A/C serials Clock Control Unit Device Tree Bindings
> +
> +maintainers:
> +  - Neil Armstrong <narmstrong@baylibre.com>
> +  - Jerome Brunet <jbrunet@baylibre.com>
> +  - Jian Hu <jian.hu@jian.hu.com>
> +
> +description: |+
> +  The clock controller node should be the child of a syscon node with the
> +  required property:
> +
> +  - compatible:         Should be one of the following:
> +                        "amlogic,meson-a-analog-sysctrl", "syscon", "simple-mfd"
> +                        "amlogic,meson-a-periphs-sysctrl", "syscon", "simple-mfd"
> +
> +  Refer to the the bindings described in
> +  Documentation/devicetree/bindings/mfd/syscon.txt
> +
> +properties:
> +  "#clock-cells":
> +    const: 1
> +  compatible:
> +    - enum:
> +        - amlogic,a1-periphs-clkc
> +        - amlogic,a1-pll-clkc
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    minItems: 2
> +    maxItems: 6
> +
> +  clock-names:
> +    minItems: 2
> +    maxItems: 6
> +
> +required:
> +  - "#clock-cells"
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +
> +if:
> +  properties:
> +    compatible:
> +      enum:
> +        - amlogic,a1-periphs-clkc
> +
> +then:
> +  properties:
> +    clocks:
> +      minItems: 2
> +      maxItems: 2
> +    items:
> +     - description: fixed pll gate clock
> +     - description: hifi pll gate clock
> +
> +    clock-names:
> +      minItems: 2
> +      maxItems: 2
> +      items:
> +        - const: xtal_fixpll
> +        - const: xtal_hifipll
> +
> +else:
> +  if:
> +    properties:
> +      compatible:
> +        const: amlogic,a1-pll-clkc
> +
> +  then:
> +    properties:
> +      clocks:
> +        minItems: 6
> +        maxItems: 6
> +        items:
> +         - description: Input fixed pll div2
> +         - description: Input fixed pll div3
> +         - description: Input fixed pll div5
> +         - description: Input fixed pll div7
> +         - description: Periph Hifi pll
> +         - description: Input Oscillator (usually at 24MHz)
> +
> +      clock-names:
> +        minItems: 6
> +        maxItems: 6
> +        items:
> +         - const: fclk_div2
> +         - const: fclk_div3
> +         - const: fclk_div5
> +         - const: fclk_div7
> +         - const: hifi_pll
> +         - const: xtal
> +
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    analog: system-controller@0 {
> +        compatible = "amlogic,meson-a-analog-sysctrl",
> +                     "simple-mfd", "syscon";
> +        reg = <0 0x7c00 0 0x21c>;
> +
> +        clkc_pll: pll-clock-controller {
> +                compatible = "amlogic,a1-pll-clkc";
> +                #clock-cells = <1>;
> +                clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
> +                         <&clkc_periphs CLKID_XTAL_HIFIPLL>;
> +                clock-names = "xtal_fixpll", "xtal_hifipll";
> +        };
> +    };
> +
> +  - |
> +    periphs: system-controller@1 {
> +        compatible = "amlogic,meson-a-periphs-sysctrl",
> +                     "simple-mfd", "syscon";
> +        reg = <0 0x800 0 0x104>;
> +
> +        clkc_periphs: periphs-clock-controller {
> +                compatible = "amlogic,a1-periphs-clkc";
> +                #clock-cells = <1>;
> +                clocks = <&clkc_pll CLKID_FCLK_DIV2>,
> +                        <&clkc_pll CLKID_FCLK_DIV3>,
> +                        <&clkc_pll CLKID_FCLK_DIV5>,
> +                        <&clkc_pll CLKID_FCLK_DIV7>,
> +                        <&clkc_pll CLKID_HIFI_PLL>,
> +                        <&xtal>;
> +                clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
> +                              "fclk_div7", "hifi_pll", "xtal";
> +        };
> +    };
> diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h
> new file mode 100644
> index 0000000..1ba0112
> --- /dev/null
> +++ b/include/dt-bindings/clock/a1-clkc.h
> @@ -0,0 +1,98 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#ifndef __A1_CLKC_H
> +#define __A1_CLKC_H
> +
> +#define CLKID_XTAL_FIXPLL			1
> +#define CLKID_XTAL_USB_PHY			2
> +#define CLKID_XTAL_USB_CTRL			3
> +#define CLKID_XTAL_HIFIPLL			4
> +#define CLKID_XTAL_SYSPLL			5
> +#define CLKID_XTAL_DDS				6
> +#define CLKID_SYS_CLK				7
> +#define CLKID_CLKTREE				8
> +#define CLKID_RESET_CTRL			9
> +#define CLKID_ANALOG_CTRL			10
> +#define CLKID_PWR_CTRL				11
> +#define CLKID_PAD_CTRL				12
> +#define CLKID_SYS_CTRL				13
> +#define CLKID_TEMP_SENSOR			14
> +#define CLKID_AM2AXI_DIV			15
> +#define CLKID_SPICC_B				16
> +#define CLKID_SPICC_A				17
> +#define CLKID_CLK_MSR				18
> +#define CLKID_AUDIO				19
> +#define CLKID_JTAG_CTRL				20
> +#define CLKID_SARADC				21
> +#define CLKID_PWM_EF				22
> +#define CLKID_PWM_CD				23
> +#define CLKID_PWM_AB				24
> +#define CLKID_CEC				25
> +#define CLKID_I2C_S				26
> +#define CLKID_IR_CTRL				27
> +#define CLKID_I2C_M_D				28
> +#define CLKID_I2C_M_C				29
> +#define CLKID_I2C_M_B				30
> +#define CLKID_I2C_M_A				31
> +#define CLKID_ACODEC				32
> +#define CLKID_OTP				33
> +#define CLKID_SD_EMMC_A				34
> +#define CLKID_USB_PHY				35
> +#define CLKID_USB_CTRL				36
> +#define CLKID_SYS_DSPB				37
> +#define CLKID_SYS_DSPA				38
> +#define CLKID_DMA				39
> +#define CLKID_IRQ_CTRL				40
> +#define CLKID_NIC				41
> +#define CLKID_GIC				42
> +#define CLKID_UART_C				43
> +#define CLKID_UART_B				44
> +#define CLKID_UART_A				45
> +#define CLKID_SYS_PSRAM				46
> +#define CLKID_RSA				47
> +#define CLKID_CORESIGHT				48
> +#define CLKID_AM2AXI_VAD			49
> +#define CLKID_AUDIO_VAD				50
> +#define CLKID_AXI_DMC				51
> +#define CLKID_AXI_PSRAM				52
> +#define CLKID_RAMB				53
> +#define CLKID_RAMA				54
> +#define CLKID_AXI_SPIFC				55
> +#define CLKID_AXI_NIC				56
> +#define CLKID_AXI_DMA				57
> +#define CLKID_CPU_CTRL				58
> +#define CLKID_ROM				59
> +#define CLKID_PROC_I2C				60
> +#define CLKID_DSPA_SEL				61
> +#define CLKID_DSPB_SEL				62
> +#define CLKID_DSPA_EN_DSPA			63
> +#define CLKID_DSPA_EN_NIC			64
> +#define CLKID_DSPB_EN_DSPB			65
> +#define CLKID_DSPB_EN_NIC			66
> +#define CLKID_RTC_CLK				67
> +#define CLKID_CECA_32K				68
> +#define CLKID_CECB_32K				69
> +#define CLKID_24M				70
> +#define CLKID_12M				71
> +#define CLKID_FCLK_DIV2_DIVN			72
> +#define CLKID_GEN				73
> +#define CLKID_SARADC_SEL			74
> +#define CLKID_SARADC_CLK			75
> +#define CLKID_PWM_A				76
> +#define CLKID_PWM_B				77
> +#define CLKID_PWM_C				78
> +#define CLKID_PWM_D				79
> +#define CLKID_PWM_E				80
> +#define CLKID_PWM_F				81
> +#define CLKID_SPICC				82
> +#define CLKID_TS				83
> +#define CLKID_SPIFC				84
> +#define CLKID_USB_BUS				85
> +#define CLKID_SD_EMMC				86
> +#define CLKID_PSRAM				87
> +#define CLKID_DMC				88
> +
> +#endif /* __A1_CLKC_H */
> diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
> new file mode 100644
> index 0000000..58eae23
> --- /dev/null
> +++ b/include/dt-bindings/clock/a1-pll-clkc.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#ifndef __A1_PLL_CLKC_H
> +#define __A1_PLL_CLKC_H
> +
> +#define CLKID_FIXED_PLL				1
> +#define CLKID_FCLK_DIV2				6
> +#define CLKID_FCLK_DIV3				7
> +#define CLKID_FCLK_DIV5				8
> +#define CLKID_FCLK_DIV7				9
> +#define CLKID_HIFI_PLL				10
> +
> +#endif /* __A1_PLL_CLKC_H */


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

* Re: [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops
  2019-10-18  7:14 ` [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops Jian Hu
@ 2019-10-21 11:31   ` Jerome Brunet
  2019-10-25  6:47     ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-10-21 11:31 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree


On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:

> The A1 PLL design is different with previous SoCs. The PLL
> internal analog modules Power-on sequence is different
> with previous, and thus requires a strict register sequence to
> enable the PLL. Unlike the previous series, the maximum frequency
> is 6G in G12A, for A1 the maximum is 1536M.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
>  drivers/clk/meson/clk-pll.c | 66 ++++++++++++++++++++++++++++++++++++++++-----
>  drivers/clk/meson/clk-pll.h |  1 +
>  2 files changed, 61 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
> index ddb1e56..b440e62 100644
> --- a/drivers/clk/meson/clk-pll.c
> +++ b/drivers/clk/meson/clk-pll.c
> @@ -349,6 +349,56 @@ static void meson_clk_pll_disable(struct clk_hw *hw)
>  	meson_parm_write(clk->map, &pll->en, 0);
>  }
>  
> +/*
> + * The A1 design is different with previous SoCs.The PLL
> + * internal analog modules Power-on sequence is different with
> + * previous, different PLL has the different sequence, and
> + * thus requires a strict register sequence to enable the PLL.
> + * When set a new target frequency, the sequence should keep
> + * the same with the initial sequence. Unlike the previous series,
> + * the maximum frequency is 6G in G12A, for A1 the maximum
> + * is 1536M.

The comment about the max frequency belongs in your a1 driver, not in
the PLL driver

> + */
> +static void meson_params_update_with_init_seq(struct clk_regmap *clk,
> +				       struct meson_clk_pll_data *pll,
> +				       unsigned int m, unsigned int n,
> +				       unsigned int frac)
> +{
> +	struct parm *pm = &pll->m;
> +	struct parm *pn = &pll->n;
> +	struct parm *pfrac = &pll->frac;
> +	const struct reg_sequence *init_regs = pll->init_regs;
> +	unsigned int i, val;
> +
> +	for (i = 0; i < pll->init_count; i++) {
> +		if (pn->reg_off == init_regs[i].reg) {
> +			/* Clear M N bits and Update M N value */
> +			val = init_regs[i].def;
> +			val &= CLRPMASK(pn->width, pn->shift);
> +			val &= CLRPMASK(pm->width, pm->shift);
> +			val |= n << pn->shift;
> +			val |= m << pm->shift;
> +			regmap_write(clk->map, pn->reg_off, val);
> +		} else if (MESON_PARM_APPLICABLE(&pll->frac) &&
> +			   (pfrac->reg_off == init_regs[i].reg)) {
> +			/* Clear Frac bits and Update Frac value */
> +			val = init_regs[i].def;
> +			val &= CLRPMASK(pfrac->width, pfrac->shift);
> +			val |= frac << pfrac->shift;
> +			regmap_write(clk->map, pfrac->reg_off, val);
> +		} else {
> +			/*
> +			 * According to the PLL hardware constraint,
> +			 * the left registers should be setted again.
> +			 */
> +			val = init_regs[i].def;
> +			regmap_write(clk->map, init_regs[i].reg, val);
> +		}
> +		if (init_regs[i].delay_us)
> +			udelay(init_regs[i].delay_us);
> +	}

So:

1) All the code above this there make the PLL lock, IOW enable the
PLL. It does not belong in the set_rate() callback but in enable() or
prepare() maybe.

2) All the above is works but it is a bit over complicated for what it
does. From the a1_hifi_init_regs I see, all you really need to do is
  * toggle BIT(6) in CTRL2
  * toggle BIT(28) in CTRL0 (enable PARM)
  * toggle BIT(26) in CTRL0

You could use PARM 'rst' for one them and introduce another parm for the
other one. You would not need to repoke the whole sequence this way.

> +}
> +
>  static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  				  unsigned long parent_rate)
>  {
> @@ -366,16 +416,20 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>  	if (ret)
>  		return ret;
>  
> +	if (MESON_PARM_APPLICABLE(&pll->frac))
> +		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
> +
>  	enabled = meson_parm_read(clk->map, &pll->en);
>  	if (enabled)
>  		meson_clk_pll_disable(hw);
>  
> -	meson_parm_write(clk->map, &pll->n, n);
> -	meson_parm_write(clk->map, &pll->m, m);
> -
> -	if (MESON_PARM_APPLICABLE(&pll->frac)) {
> -		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
> -		meson_parm_write(clk->map, &pll->frac, frac);
> +	if (pll->strict_sequence)
> +		meson_params_update_with_init_seq(clk, pll, m, n, frac);
> +	else {
> +		meson_parm_write(clk->map, &pll->n, n);
> +		meson_parm_write(clk->map, &pll->m, m);
> +		if (MESON_PARM_APPLICABLE(&pll->frac))
> +			meson_parm_write(clk->map, &pll->frac, frac);
>  	}
>  
>  	/* If the pll is stopped, bail out now */
> diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h
> index 367efd0..d5789cef 100644
> --- a/drivers/clk/meson/clk-pll.h
> +++ b/drivers/clk/meson/clk-pll.h
> @@ -41,6 +41,7 @@ struct meson_clk_pll_data {
>  	const struct pll_params_table *table;
>  	const struct pll_mult_range *range;
>  	u8 flags;
> +	bool strict_sequence;

Don't introduce parameter for this We have ops to tune the behavior of
the clock driver. Properly refactor the code if some of it is common.

>  };
>  
>  extern const struct clk_ops meson_clk_pll_ro_ops;


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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-18  7:14 ` [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
@ 2019-10-21 11:41   ` Jerome Brunet
  2019-10-25 11:32     ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-10-21 11:41 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:

> The Amlogic A1 clock includes three drivers:
> peripheral clocks, pll clocks, CPU clocks.
> sys pll and CPU clocks will be sent in next patch.
>
> Unlike the previous series, there is no EE/AO domain
> in A1 CLK controllers.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
>  drivers/clk/meson/Kconfig  |   10 +
>  drivers/clk/meson/Makefile |    1 +
>  drivers/clk/meson/a1-pll.c |  345 +++++++
>  drivers/clk/meson/a1-pll.h |   56 ++
>  drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/a1.h     |  120 +++
>  6 files changed, 2796 insertions(+)
>  create mode 100644 drivers/clk/meson/a1-pll.c
>  create mode 100644 drivers/clk/meson/a1-pll.h
>  create mode 100644 drivers/clk/meson/a1.c
>  create mode 100644 drivers/clk/meson/a1.h

In the next version, one

>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index dabeb43..c2809b2 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>  	  Support for the audio clock controller on AmLogic A113D devices,
>  	  aka axg, Say Y if you want audio subsystem to work.
>  
> +config COMMON_CLK_A1
> +	bool
> +	depends on ARCH_MESON
> +	select COMMON_CLK_MESON_REGMAP
> +	select COMMON_CLK_MESON_DUALDIV
> +	select COMMON_CLK_MESON_PLL
> +	help
> +	  Support for the clock controller on Amlogic A113L device,
> +	  aka a1. Say Y if you want peripherals to work.
> +
>  config COMMON_CLK_G12A
>  	bool
>  	depends on ARCH_MESON
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 3939f21..28cbae1 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>  
>  obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o

So far, all the controller had there own option, I don't see why it
should be different here.

>  obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
> new file mode 100644
> index 0000000..486d964
> --- /dev/null
> +++ b/drivers/clk/meson/a1-pll.c
> @@ -0,0 +1,345 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <jian.hu@amlogic.com>
> + */
> +
> +#include <linux/platform_device.h>

Hum ... looks like some things are missing here

#include <linux/of_device.h>
#include <linux/clk-provider.h>

?

> +#include "clk-pll.h"
> +#include "meson-eeclk.h"
> +#include "a1-pll.h"

Alphanumeric order please

> +
> +static struct clk_regmap a1_fixed_pll_dco = {
> +	.data = &(struct meson_clk_pll_data){
> +		.en = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.m = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
> +			.shift   = 0,
> +			.width   = 8,
> +		},
> +		.n = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
> +			.shift   = 10,
> +			.width   = 5,
> +		},
> +		.frac = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
> +			.shift   = 0,
> +			.width   = 19,
> +		},
> +		.l = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
> +			.shift   = 31,
> +			.width   = 1,
> +		},
> +		.rst = {
> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
> +			.shift   = 29,
> +			.width   = 1,
> +		},
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fixed_pll_dco",
> +		.ops = &meson_clk_pll_ro_ops,
> +		.parent_data = &(const struct clk_parent_data){
> +			.fw_name = "xtal_fixpll",
> +			.name = "xtal_fixpll",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fixed_pll = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = ANACTRL_FIXPLL_CTRL0,
> +		.bit_idx = 20,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "fixed_pll",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fixed_pll_dco.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is fclk_div2/3/4's parent,
> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.

is it fclk_div2/3/4 or fclk_div2/3/5 ?

> +		 * It is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */

Don't blindly copy/paste comments from other drivers. There is no driver
for the devices you are mentionning so the end of the comment is
confusing. The 3 first lines were enough

> +		.flags = CLK_IS_CRITICAL,

From your comment, I understand that some child are critical, not this
particular (or at least, not directly). So this can be removed AFAICT

You should even need CLK_IGNORE_UNUSED for this one since the clock will
already be enabled before the late_init() kicks in

> +	},
> +};
> +
> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
> +	.min = 32,
> +	.max = 64,
> +};
> +
> +static const struct reg_sequence a1_hifi_init_regs[] = {
> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
> +};
> +
> +static struct clk_regmap a1_hifi_pll = {
> +	.data = &(struct meson_clk_pll_data){
> +		.en = {
> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.m = {
> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
> +			.shift   = 0,
> +			.width   = 8,
> +		},
> +		.n = {
> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
> +			.shift   = 10,
> +			.width   = 5,
> +		},
> +		.frac = {
> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
> +			.shift   = 0,
> +			.width   = 19,
> +		},
> +		.l = {
> +			.reg_off = ANACTRL_HIFIPLL_STS,
> +			.shift   = 31,
> +			.width   = 1,
> +		},
> +		.range = &a1_hifi_pll_mult_range,
> +		.init_regs = a1_hifi_init_regs,
> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
> +		.strict_sequence = true,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "hifi_pll",
> +		.ops = &meson_clk_pll_ops,
> +		.parent_data = &(const struct clk_parent_data){
> +			.fw_name = "xtal_fixpll",
> +			.name = "xtal_fixpll",

Both should provided when a controller transition from the old way of
describing parent to the new way. This is a new controller so it does
not apply.

Same for the other occurences.

Also, I think you meant xtal_hifipll

> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_fixed_factor a1_fclk_div2_div = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div2_div",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fixed_pll.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div2 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = ANACTRL_FIXPLL_CTRL0,
> +		.bit_idx = 21,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div2",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by DDR clock in BL2 firmware
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +static struct clk_fixed_factor a1_fclk_div3_div = {
> +	.mult = 1,
> +	.div = 3,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div3_div",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fixed_pll.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div3 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = ANACTRL_FIXPLL_CTRL0,
> +		.bit_idx = 22,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div3",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div3_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by APB bus which setted in Romcode
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +static struct clk_fixed_factor a1_fclk_div5_div = {
> +	.mult = 1,
> +	.div = 5,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div5_div",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fixed_pll.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div5 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = ANACTRL_FIXPLL_CTRL0,
> +		.bit_idx = 23,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div5",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div5_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by AXI bus which setted in Romcode
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +static struct clk_fixed_factor a1_fclk_div7_div = {
> +	.mult = 1,
> +	.div = 7,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div7_div",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fixed_pll.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div7 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = ANACTRL_FIXPLL_CTRL0,
> +		.bit_idx = 24,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div7",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div7_div.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +/* Array of all clocks provided by this provider */
> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
> +	.hws = {
> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
> +		[NR_PLL_CLKS]			= NULL,
> +	},
> +	.num = NR_PLL_CLKS,
> +};
> +
> +static struct clk_regmap *const a1_pll_regmaps[] = {
> +	&a1_fixed_pll_dco,
> +	&a1_fixed_pll,
> +	&a1_hifi_pll,
> +	&a1_fclk_div2,
> +	&a1_fclk_div3,
> +	&a1_fclk_div5,
> +	&a1_fclk_div7,
> +};
> +
> +static int meson_a1_pll_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +
> +	ret = meson_eeclkc_probe(pdev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}

This function is useless.

> +
> +static const struct meson_eeclkc_data a1_pll_data = {
> +		.regmap_clks = a1_pll_regmaps,
> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
> +};
> +static const struct of_device_id clkc_match_table[] = {
> +	{
> +		.compatible = "amlogic,a1-pll-clkc",
> +		.data = &a1_pll_data
> +	},
> +	{ /* sentinel */ }

Nitpick: don't need to write this, just write the line like this

' }, {}'

> +};
> +
> +static struct platform_driver a1_driver = {
> +	.probe		= meson_a1_pll_probe,
> +	.driver		= {
> +		.name	= "a1-pll-clkc",
> +		.of_match_table = clkc_match_table,
> +	},
> +};
> +
> +builtin_platform_driver(a1_driver);
> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
> new file mode 100644
> index 0000000..99ee2a9
> --- /dev/null
> +++ b/drivers/clk/meson/a1-pll.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#ifndef __A1_PLL_H
> +#define __A1_PLL_H
> +
> +/* PLL register offset */
> +#define ANACTRL_FIXPLL_CTRL0		0x80
> +#define ANACTRL_FIXPLL_CTRL1		0x84
> +#define ANACTRL_FIXPLL_CTRL2		0x88
> +#define ANACTRL_FIXPLL_CTRL3		0x8c
> +#define ANACTRL_FIXPLL_CTRL4		0x90
> +#define ANACTRL_FIXPLL_STS		0x94
> +#define ANACTRL_SYSPLL_CTRL0		0x100
> +#define ANACTRL_SYSPLL_CTRL1		0x104
> +#define ANACTRL_SYSPLL_CTRL2		0x108
> +#define ANACTRL_SYSPLL_CTRL3		0x10c
> +#define ANACTRL_SYSPLL_CTRL4		0x110
> +#define ANACTRL_SYSPLL_STS		0x114
> +#define ANACTRL_HIFIPLL_CTRL0		0x140
> +#define ANACTRL_HIFIPLL_CTRL1		0x144
> +#define ANACTRL_HIFIPLL_CTRL2		0x148
> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
> +#define ANACTRL_HIFIPLL_CTRL4		0x150
> +#define ANACTRL_HIFIPLL_STS		0x154
> +#define ANACTRL_AUDDDS_CTRL0		0x180
> +#define ANACTRL_AUDDDS_CTRL1		0x184
> +#define ANACTRL_AUDDDS_CTRL2		0x188
> +#define ANACTRL_AUDDDS_CTRL3		0x18c
> +#define ANACTRL_AUDDDS_CTRL4		0x190
> +#define ANACTRL_AUDDDS_STS		0x194
> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
> +#define ANACTRL_POR_CNTL		0x208
> +
> +/*
> + * CLKID index values
> + *
> + * These indices are entirely contrived and do not map onto the hardware.
> + * It has now been decided to expose everything by default in the DT header:
> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
> + * to expose, such as the internal muxes and dividers of composite clocks,
> + * will remain defined here.
> + */
> +#define CLKID_FIXED_PLL_DCO		0
> +#define CLKID_FCLK_DIV2_DIV		2
> +#define CLKID_FCLK_DIV3_DIV		3
> +#define CLKID_FCLK_DIV5_DIV		4
> +#define CLKID_FCLK_DIV7_DIV		5
> +#define NR_PLL_CLKS			11
> +
> +/* include the CLKIDs that have been made part of the DT binding */
> +#include <dt-bindings/clock/a1-pll-clkc.h>
> +
> +#endif /* __A1_PLL_H */
> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
> new file mode 100644
> index 0000000..86a4733
> --- /dev/null
> +++ b/drivers/clk/meson/a1.c
> @@ -0,0 +1,2264 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <jian.hu@amlogic.com>
> + */
> +
> +#include <linux/platform_device.h>
> +#include "clk-pll.h"
> +#include "clk-dualdiv.h"
> +#include "meson-eeclk.h"
> +#include "a1.h"

Same as above

> +
> +/* PLLs clock in gates, its parent is xtal */
> +static struct clk_regmap a1_xtal_clktree = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 0,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_clktree",
> +		.ops = &clk_regmap_gate_ro_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * switch for xtal clock
> +		 * Linux should not change it at runtime
> +		 */

Comment not useful: it uses the Ro ops

> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_fixpll = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 1,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_fixpll",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_IS_CRITICAL,
> +		/*
> +		 * it feeds DDR,AXI,APB bus
> +		 * Linux should not change it at runtime
> +		 */

Again, the child are critical, not directly this clock from your
comment.

Remove CRITICAL, put RO is linux is not supposed to touch it.

> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_usb_phy = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 2,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_usb_phy",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_usb_ctrl = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 3,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_usb_ctrl",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_hifipll = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 4,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_hifipll",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_syspll = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 5,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_syspll",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_xtal_dds = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_OSCIN_CTRL,
> +		.bit_idx = 6,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "xtal_dds",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static const struct clk_parent_data sys_clk_parents[] = {
> +	{ .fw_name = "xtal" },
> +	{ .fw_name = "fclk_div2"},
> +	{ .fw_name = "fclk_div3"},
> +	{ .fw_name = "fclk_div5"},
> +};
> +
> +static struct clk_regmap a1_sys_b_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 26,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_b_sel",
> +		.ops = &clk_regmap_mux_ro_ops,
> +		.parent_data = sys_clk_parents,
> +		.num_parents = ARRAY_SIZE(sys_clk_parents),
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_b_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.shift = 16,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_b_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sys_b_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_b = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.bit_idx = 29,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "sys_b",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sys_b_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by APB bus which setted in Romcode
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_a_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_a_sel",
> +		.ops = &clk_regmap_mux_ro_ops,
> +		.parent_data = sys_clk_parents,
> +		.num_parents = ARRAY_SIZE(sys_clk_parents),
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_a_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.shift = 0,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_a_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sys_a_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_a = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.bit_idx = 13,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "sys_a",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sys_a_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by APB bus which setted in Romcode
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> +	},
> +};
> +
> +static struct clk_regmap a1_sys_clk = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_clk",
> +		.ops = &clk_regmap_mux_ro_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sys_a.hw, &a1_sys_b.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* rtc 32k clock in */
> +static struct clk_regmap a1_rtc_32k_clkin = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_32k_clkin",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static const struct meson_clk_dualdiv_param a1_32k_div_table[] = {
> +	{
> +		.dual		= 1,
> +		.n1		= 733,
> +		.m1		= 8,
> +		.n2		= 732,
> +		.m2		= 11,
> +	}, {}
> +};
> +
> +static struct clk_regmap a1_rtc_32k_div = {
> +	.data = &(struct meson_clk_dualdiv_data){
> +		.n1 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = RTC_BY_OSCIN_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = RTC_BY_OSCIN_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a1_32k_div_table,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "rtc_32k_div",
> +		.ops = &meson_clk_dualdiv_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_rtc_32k_clkin.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_rtc_32k_xtal = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = RTC_BY_OSCIN_CTRL1,
> +		.bit_idx = 24,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "rtc_32k_xtal",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_rtc_32k_clkin.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static u32 rtc_32k_sel[] = { 0, 1 };
> +
> +static struct clk_regmap a1_rtc_32k_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = RTC_CTRL,
> +		.mask = 0x3,
> +		.shift = 0,
> +		.table = rtc_32k_sel,
> +		.flags = CLK_MUX_ROUND_CLOSEST,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "rtc_32k_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_rtc_32k_xtal.hw,
> +			&a1_rtc_32k_div.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +struct clk_regmap a1_rtc_clk = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "rtc_clk",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_rtc_32k_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* dsp a clk */
> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fclk_div2", },
> +	{ .fw_name = "fclk_div3", },
> +	{ .fw_name = "fclk_div5", },
> +	{ .fw_name = "hifi_pll", },
> +	{ .hw = &a1_rtc_clk.hw },
> +};
> +
> +static struct clk_regmap a1_dspa_a_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 10,
> +		.table = mux_table_dsp_ab,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspa_a_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = dsp_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),

.flags = CLK_SET_RATE_PARENT ?

> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_a_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.shift = 0,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspa_a_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_a_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_a = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.bit_idx = 13,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_a",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_a_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_b_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 26,
> +		.table = mux_table_dsp_ab,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspa_b_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = dsp_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),

.flags = CLK_SET_RATE_PARENT ?

> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_b_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.shift = 16,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspa_b_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_b_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_b = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.bit_idx = 29,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_b",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_b_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPA_CLK_CTRL0,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspa_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_dspa_a.hw },
> +			{ .hw = &a1_dspa_b.hw },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_en_dspa = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPA_CLK_EN,
> +		.bit_idx = 1,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_en_dspa",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,

Why do you need CLK_IGNORE_UNUSED ?

> +	},
> +};
> +
> +static struct clk_regmap a1_dspa_en_nic = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPA_CLK_EN,
> +		.bit_idx = 0,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspa_en_nic",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspa_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,

Why do you need CLK_IGNORE_UNUSED ?

> +	},
> +};
> +

Same question and remarks applies to DSP B

> +/* dsp b clk */
> +static struct clk_regmap a1_dspb_a_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 10,
> +		.table = mux_table_dsp_ab,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspb_a_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = dsp_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_a_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.shift = 0,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspb_a_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_a_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_a = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.bit_idx = 13,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspb_a",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_a_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_b_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 26,
> +		.table = mux_table_dsp_ab,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspb_b_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = dsp_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_b_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.shift = 16,
> +		.width = 10,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspb_b_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_b_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_b = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.bit_idx = 29,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspb_b",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_b_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPB_CLK_CTRL0,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dspb_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_en_dspb = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPB_CLK_EN,
> +		.bit_idx = 1,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspb_en_dspb",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static struct clk_regmap a1_dspb_en_nic = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DSPB_CLK_EN,
> +		.bit_idx = 0,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dspb_en_nic",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dspb_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* 12M/24M clock */
> +static struct clk_regmap a1_24m = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "24m",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_fixed_factor a1_24m_div2 = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "24m_div2",
> +		.ops = &clk_fixed_factor_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_24m.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_12m = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 10,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "12m",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_24m_div2.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div2_divn_pre = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = CLK12_24_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div2_divn_pre",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "fclk_div2",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_fclk_div2_divn = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 12,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "fclk_div2_divn",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2_divn_pre.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* gen clk */
> +/*
> + * the second parent is sys_pll_div16, it will complete in the CPU clock,
> + * the forth parent is the clock measurement source, it relies on
> + * the clock measurement register configuration.
> + */
> +static u32 gen_clk_table[] = { 0, 1, 3, 5, 6, 7, 8 };
> +static const struct clk_parent_data gen_clk_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_rtc_clk.hw },
> +	{ .fw_name = "hifi_pll", },
> +	{ .fw_name = "fclk_div2", },
> +	{ .fw_name = "fclk_div3", },
> +	{ .fw_name = "fclk_div5", },
> +	{ .fw_name = "fclk_div7", },
> +};
> +
> +static struct clk_regmap a1_gen_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = GEN_CLK_CTRL,
> +		.mask = 0xf,
> +		.shift = 12,
> +		.table = gen_clk_table,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "gen_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = gen_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(gen_clk_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_gen_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = GEN_CLK_CTRL,
> +		.shift = 0,
> +		.width = 11,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "gen_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_gen_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_gen = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = GEN_CLK_CTRL,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "gen",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_gen_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_saradc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SAR_ADC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "saradc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .fw_name = "xtal", },
> +			{ .hw = &a1_sys_clk.hw, },
> +		},
> +		.num_parents = 2,
> +	},
> +};
> +
> +static struct clk_regmap a1_saradc_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SAR_ADC_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "saradc_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_saradc_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_saradc_clk = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SAR_ADC_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "saradc_clk",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_saradc_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* pwm a/b/c/d parent data */
> +static const struct clk_parent_data pwm_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_sys_clk.hw },
> +};

Looks like the same as SAR ADC

> +
> +/* pwm a clk */
> +static struct clk_regmap a1_pwm_a_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.mask = 0x1,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_a_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_a_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_a_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_a_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_a = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_a",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_a_div.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * The CPU working voltage is controlled by pwm_a
> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
> +		 * to avoid changing at runtime.
                                    ^ it

> +		 * and is required by the platform to operate correctly.
                   "blabla. And" is strange

> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,

This only skips the late_init() disable of unused clocks

Be aware that this is not fool-proof. If at any time a driver enable
then disable the clock, the clock will be disable and I guess your
platform will die if this provides the CPU voltage.

> +	},
> +};
> +
> +/* pwm b clk */
> +static struct clk_regmap a1_pwm_b_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.mask = 0x1,
> +		.shift = 25,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_b_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_b_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.shift = 16,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_b_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_b_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_b = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_AB_CTRL,
> +		.bit_idx = 24,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_b",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_b_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* pwm c clk */
> +static struct clk_regmap a1_pwm_c_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.mask = 0x1,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_c_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_c_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_c_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_c_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_c = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_c",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_c_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* pwm d clk */
> +static struct clk_regmap a1_pwm_d_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.mask = 0x1,
> +		.shift = 25,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_d_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_d_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.shift = 16,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_d_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_d_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_d = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_CD_CTRL,
> +		.bit_idx = 24,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_d",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_d_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static const struct clk_parent_data pwm_ef_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_sys_clk.hw },
> +	{ .fw_name = "fclk_div5", },
> +	{ .hw = &a1_rtc_clk.hw },
> +};
> +
> +/* pwm e clk */
> +static struct clk_regmap a1_pwm_e_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_e_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_ef_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_e_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_e_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_e_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_e = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_e",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_e_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* pwm f clk */
> +static struct clk_regmap a1_pwm_f_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.mask = 0x3,
> +		.shift = 25,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_f_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = pwm_ef_parent_data,
> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_f_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.shift = 16,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "pwm_f_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_f_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_pwm_f = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PWM_CLK_EF_CTRL,
> +		.bit_idx = 24,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "pwm_f",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_pwm_f_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* spicc clk */
> +
> +/*    div2   |\         |\       _____
> + *  ---------| |---DIV--| |     |     |    spicc out
> + *  ---------| |        | |-----|GATE |---------
> + *     ..... |/         | /     |_____|
> + *  --------------------|/
> + *                 24M
> + */
> +static const struct clk_parent_data spicc_parents[] = {
> +	{ .fw_name = "fclk_div2"},
> +	{ .fw_name = "fclk_div3"},
> +	{ .fw_name = "fclk_div5"},
> +	{ .fw_name = "hifi_pll" },
> +};
> +
> +static struct clk_regmap a1_spicc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SPICC_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spicc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = spicc_parents,
> +		.num_parents = 4,
> +	},
> +};
> +
> +static struct clk_regmap a1_spicc_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SPICC_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spicc_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_spicc_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_spicc_sel2 = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SPICC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spicc_sel2",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_spicc_div.hw },
> +			{ .fw_name = "xtal", },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_spicc = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SPICC_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "spicc",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_spicc_sel2.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* ts clk */
> +static struct clk_regmap a1_ts_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = TS_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "ts_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_ts = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = TS_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "ts",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_ts_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* spifc clk */
> +static struct clk_regmap a1_spifc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SPIFC_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spifc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		/* the same parent with spicc */
> +		.parent_data = spicc_parents,
> +		.num_parents = 4,
> +	},
> +};
> +
> +static struct clk_regmap a1_spifc_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SPIFC_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spifc_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_spifc_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_spifc_sel2 = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SPIFC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "spifc_sel2",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_spifc_div.hw },
> +			{ .fw_name = "xtal", },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_spifc = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SPIFC_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "spifc",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_spifc_sel2.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* usb bus clk */
> +static const struct clk_parent_data usb_bus_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_sys_clk.hw },
> +	{ .fw_name = "fclk_div3", },
> +	{ .fw_name = "fclk_div5", },
> +};
> +
> +static struct clk_regmap a1_usb_bus_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = USB_BUSCLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "usb_bus_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = usb_bus_parent_data,
> +		.num_parents = ARRAY_SIZE(usb_bus_parent_data),
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_usb_bus_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = USB_BUSCLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "usb_bus_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_usb_bus_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_usb_bus = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = USB_BUSCLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "usb_bus",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_usb_bus_div.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* sd emmc clk */
> +static const struct clk_parent_data sd_emmc_parents[] = {
> +	{ .fw_name = "fclk_div2", },
> +	{ .fw_name = "fclk_div3", },
> +	{ .fw_name = "fclk_div5", },
> +	{ .fw_name = "hifi_pll", },
> +};
> +
> +static struct clk_regmap a1_sd_emmc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SD_EMMC_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sd_emmc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = sd_emmc_parents,
> +		.num_parents = 4,
> +	},
> +};
> +
> +static struct clk_regmap a1_sd_emmc_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = SD_EMMC_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sd_emmc_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sd_emmc_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_sd_emmc_sel2 = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SD_EMMC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sd_emmc_sel2",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_sd_emmc_div.hw },
> +			{ .fw_name = "xtal", },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_sd_emmc = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = SD_EMMC_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "sd_emmc",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_sd_emmc_sel2.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_psram_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PSRAM_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "psram_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		/* the same parent with sd_emmc */
> +		.parent_data = sd_emmc_parents,
> +		.num_parents = 4,
> +	},
> +};
> +
> +static struct clk_regmap a1_psram_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = PSRAM_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "psram_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_psram_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_psram_sel2 = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = PSRAM_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "psram_sel2",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_psram_div.hw },
> +			{ .fw_name = "xtal", },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_psram = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = PSRAM_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "psram",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_psram_sel2.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* dmc clk */
> +static struct clk_regmap a1_dmc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DMC_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dmc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = sd_emmc_parents,
> +		.num_parents = 4,
> +	},
> +};
> +
> +static struct clk_regmap a1_dmc_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = DMC_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dmc_div",
> +		.ops = &clk_regmap_divider_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dmc_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dmc_sel2 = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DMC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "dmc_sel2",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_data = (const struct clk_parent_data []) {
> +			{ .hw = &a1_dmc_div.hw },
> +			{ .fw_name = "xtal", },
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_dmc = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = DMC_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "dmc",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_dmc_sel2.hw
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * This clock is used by DDR clock which setted in BL2
> +		 * and is required by the platform to operate correctly.
> +		 * Until the following condition are met, we need this clock to
> +		 * be marked as critical:
> +		 * a) Mark the clock used by a firmware resource, if possible
> +		 * b) CCF has a clock hand-off mechanism to make the sure the
> +		 *    clock stays on until the proper driver comes along
> +		 */
> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> +	},
> +};

Should you put all this DMC stuff in RO until you got a driver for it ?

> +
> +/* cec A clock */
> +static struct clk_regmap a1_ceca_32k_clkin = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CECA_CLK_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "ceca_32k_clkin",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_ceca_32k_div = {
> +	.data = &(struct meson_clk_dualdiv_data){
> +		.n1 = {
> +			.reg_off = CECA_CLK_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = CECA_CLK_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = CECA_CLK_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = CECA_CLK_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = CECA_CLK_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a1_32k_div_table,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "ceca_32k_div",
> +		.ops = &meson_clk_dualdiv_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_ceca_32k_clkin.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_ceca_32k_sel_pre = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = CECA_CLK_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +		.flags = CLK_MUX_ROUND_CLOSEST,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "ceca_32k_sel_pre",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_ceca_32k_div.hw,
> +			&a1_ceca_32k_clkin.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_ceca_32k_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = CECA_CLK_CTRL1,
> +		.mask = 0x1,
> +		.shift = 31,
> +		.flags = CLK_MUX_ROUND_CLOSEST,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "ceca_32k_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_ceca_32k_sel_pre.hw,
> +			&a1_rtc_clk.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_ceca_32k_clkout = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CECA_CLK_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "ceca_32k_clkout",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_ceca_32k_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +/* cec B clock */
> +static struct clk_regmap a1_cecb_32k_clkin = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CECB_CLK_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "cecb_32k_clkin",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_cecb_32k_div = {
> +	.data = &(struct meson_clk_dualdiv_data){
> +		.n1 = {
> +			.reg_off = CECB_CLK_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = CECB_CLK_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = CECB_CLK_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = CECB_CLK_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = CECB_CLK_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a1_32k_div_table,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "cecb_32k_div",
> +		.ops = &meson_clk_dualdiv_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_cecb_32k_clkin.hw
> +		},
> +		.num_parents = 1,
> +	},
> +};
> +
> +static struct clk_regmap a1_cecb_32k_sel_pre = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = CECB_CLK_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +		.flags = CLK_MUX_ROUND_CLOSEST,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "cecb_32k_sel_pre",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_cecb_32k_div.hw,
> +			&a1_cecb_32k_clkin.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_cecb_32k_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = CECB_CLK_CTRL1,
> +		.mask = 0x1,
> +		.shift = 31,
> +		.flags = CLK_MUX_ROUND_CLOSEST,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "cecb_32k_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_cecb_32k_sel_pre.hw,
> +			&a1_rtc_clk.hw,
> +		},
> +		.num_parents = 2,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +static struct clk_regmap a1_cecb_32k_clkout = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = CECB_CLK_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "cecb_32k_clkout",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_cecb_32k_sel.hw
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_SET_RATE_PARENT,
> +	},
> +};
> +
> +#define MESON_GATE(_name, _reg, _bit) \
> +	MESON_PCLK(_name, _reg, _bit, &a1_sys_clk.hw)
> +
> +static MESON_GATE(a1_clk_tree,		SYS_CLK_EN0,	0);
> +static MESON_GATE(a1_reset_ctrl,	SYS_CLK_EN0,	1);
> +static MESON_GATE(a1_analog_ctrl,	SYS_CLK_EN0,	2);
> +static MESON_GATE(a1_pwr_ctrl,		SYS_CLK_EN0,	3);
> +static MESON_GATE(a1_pad_ctrl,		SYS_CLK_EN0,	4);
> +static MESON_GATE(a1_sys_ctrl,		SYS_CLK_EN0,	5);
> +static MESON_GATE(a1_temp_sensor,	SYS_CLK_EN0,	6);
> +static MESON_GATE(a1_am2axi_dev,	SYS_CLK_EN0,	7);
> +static MESON_GATE(a1_spicc_b,		SYS_CLK_EN0,	8);
> +static MESON_GATE(a1_spicc_a,		SYS_CLK_EN0,	9);
> +static MESON_GATE(a1_clk_msr,		SYS_CLK_EN0,	10);
> +static MESON_GATE(a1_audio,		SYS_CLK_EN0,	11);
> +static MESON_GATE(a1_jtag_ctrl,		SYS_CLK_EN0,	12);
> +static MESON_GATE(a1_saradc,		SYS_CLK_EN0,	13);
> +static MESON_GATE(a1_pwm_ef,		SYS_CLK_EN0,	14);
> +static MESON_GATE(a1_pwm_cd,		SYS_CLK_EN0,	15);
> +static MESON_GATE(a1_pwm_ab,		SYS_CLK_EN0,	16);
> +static MESON_GATE(a1_cec,		SYS_CLK_EN0,	17);
> +static MESON_GATE(a1_i2c_s,		SYS_CLK_EN0,	18);
> +static MESON_GATE(a1_ir_ctrl,		SYS_CLK_EN0,	19);
> +static MESON_GATE(a1_i2c_m_d,		SYS_CLK_EN0,	20);
> +static MESON_GATE(a1_i2c_m_c,		SYS_CLK_EN0,	21);
> +static MESON_GATE(a1_i2c_m_b,		SYS_CLK_EN0,	22);
> +static MESON_GATE(a1_i2c_m_a,		SYS_CLK_EN0,	23);
> +static MESON_GATE(a1_acodec,		SYS_CLK_EN0,	24);
> +static MESON_GATE(a1_otp,		SYS_CLK_EN0,	25);
> +static MESON_GATE(a1_sd_emmc_a,		SYS_CLK_EN0,	26);
> +static MESON_GATE(a1_usb_phy,		SYS_CLK_EN0,	27);
> +static MESON_GATE(a1_usb_ctrl,		SYS_CLK_EN0,	28);
> +static MESON_GATE(a1_sys_dspb,		SYS_CLK_EN0,	29);
> +static MESON_GATE(a1_sys_dspa,		SYS_CLK_EN0,	30);
> +static MESON_GATE(a1_dma,		SYS_CLK_EN0,	31);
> +static MESON_GATE(a1_irq_ctrl,		SYS_CLK_EN1,	0);
> +static MESON_GATE(a1_nic,		SYS_CLK_EN1,	1);
> +static MESON_GATE(a1_gic,		SYS_CLK_EN1,	2);
> +static MESON_GATE(a1_uart_c,		SYS_CLK_EN1,	3);
> +static MESON_GATE(a1_uart_b,		SYS_CLK_EN1,	4);
> +static MESON_GATE(a1_uart_a,		SYS_CLK_EN1,	5);
> +static MESON_GATE(a1_sys_psram,		SYS_CLK_EN1,	6);
> +static MESON_GATE(a1_rsa,		SYS_CLK_EN1,	8);
> +static MESON_GATE(a1_coresight,		SYS_CLK_EN1,	9);
> +static MESON_GATE(a1_am2axi_vad,	AXI_CLK_EN,	0);
> +static MESON_GATE(a1_audio_vad,		AXI_CLK_EN,	1);
> +static MESON_GATE(a1_axi_dmc,		AXI_CLK_EN,	3);
> +static MESON_GATE(a1_axi_psram,		AXI_CLK_EN,	4);
> +static MESON_GATE(a1_ramb,		AXI_CLK_EN,	5);
> +static MESON_GATE(a1_rama,		AXI_CLK_EN,	6);
> +static MESON_GATE(a1_axi_spifc,		AXI_CLK_EN,	7);
> +static MESON_GATE(a1_axi_nic,		AXI_CLK_EN,	8);
> +static MESON_GATE(a1_axi_dma,		AXI_CLK_EN,	9);
> +static MESON_GATE(a1_cpu_ctrl,		AXI_CLK_EN,	10);
> +static MESON_GATE(a1_rom,		AXI_CLK_EN,	11);
> +static MESON_GATE(a1_prod_i2c,		AXI_CLK_EN,	12);
> +
> +/* Array of all clocks provided by this provider */
> +static struct clk_hw_onecell_data a1_periphs_hw_onecell_data = {
> +	.hws = {
> +		[CLKID_SYS_B_SEL]		= &a1_sys_b_sel.hw,
> +		[CLKID_SYS_B_DIV]		= &a1_sys_b_div.hw,
> +		[CLKID_SYS_B]			= &a1_sys_b.hw,
> +		[CLKID_SYS_A_SEL]		= &a1_sys_a_sel.hw,
> +		[CLKID_SYS_A_DIV]		= &a1_sys_a_div.hw,
> +		[CLKID_SYS_A]			= &a1_sys_a.hw,
> +		[CLKID_SYS_CLK]			= &a1_sys_clk.hw,
> +		[CLKID_XTAL_CLKTREE]		= &a1_xtal_clktree.hw,
> +		[CLKID_XTAL_FIXPLL]		= &a1_xtal_fixpll.hw,
> +		[CLKID_XTAL_USB_PHY]		= &a1_xtal_usb_phy.hw,
> +		[CLKID_XTAL_USB_CTRL]		= &a1_xtal_usb_ctrl.hw,
> +		[CLKID_XTAL_HIFIPLL]		= &a1_xtal_hifipll.hw,
> +		[CLKID_XTAL_SYSPLL]		= &a1_xtal_syspll.hw,
> +		[CLKID_XTAL_DDS]		= &a1_xtal_dds.hw,
> +		[CLKID_CLKTREE]			= &a1_clk_tree.hw,
> +		[CLKID_RESET_CTRL]		= &a1_reset_ctrl.hw,
> +		[CLKID_ANALOG_CTRL]		= &a1_analog_ctrl.hw,
> +		[CLKID_PWR_CTRL]		= &a1_pwr_ctrl.hw,
> +		[CLKID_PAD_CTRL]		= &a1_pad_ctrl.hw,
> +		[CLKID_SYS_CTRL]		= &a1_sys_ctrl.hw,
> +		[CLKID_TEMP_SENSOR]		= &a1_temp_sensor.hw,
> +		[CLKID_AM2AXI_DIV]		= &a1_am2axi_dev.hw,
> +		[CLKID_SPICC_B]			= &a1_spicc_b.hw,
> +		[CLKID_SPICC_A]			= &a1_spicc_a.hw,
> +		[CLKID_CLK_MSR]			= &a1_clk_msr.hw,
> +		[CLKID_AUDIO]			= &a1_audio.hw,
> +		[CLKID_JTAG_CTRL]		= &a1_jtag_ctrl.hw,
> +		[CLKID_SARADC]			= &a1_saradc.hw,
> +		[CLKID_PWM_EF]			= &a1_pwm_ef.hw,
> +		[CLKID_PWM_CD]			= &a1_pwm_cd.hw,
> +		[CLKID_PWM_AB]			= &a1_pwm_ab.hw,
> +		[CLKID_CEC]			= &a1_cec.hw,
> +		[CLKID_I2C_S]			= &a1_i2c_s.hw,
> +		[CLKID_IR_CTRL]			= &a1_ir_ctrl.hw,
> +		[CLKID_I2C_M_D]			= &a1_i2c_m_d.hw,
> +		[CLKID_I2C_M_C]			= &a1_i2c_m_c.hw,
> +		[CLKID_I2C_M_B]			= &a1_i2c_m_b.hw,
> +		[CLKID_I2C_M_A]			= &a1_i2c_m_a.hw,
> +		[CLKID_ACODEC]			= &a1_acodec.hw,
> +		[CLKID_OTP]			= &a1_otp.hw,
> +		[CLKID_SD_EMMC_A]		= &a1_sd_emmc_a.hw,
> +		[CLKID_USB_PHY]			= &a1_usb_phy.hw,
> +		[CLKID_USB_CTRL]		= &a1_usb_ctrl.hw,
> +		[CLKID_SYS_DSPB]		= &a1_sys_dspb.hw,
> +		[CLKID_SYS_DSPA]		= &a1_sys_dspa.hw,
> +		[CLKID_DMA]			= &a1_dma.hw,
> +		[CLKID_IRQ_CTRL]		= &a1_irq_ctrl.hw,
> +		[CLKID_NIC]			= &a1_nic.hw,
> +		[CLKID_GIC]			= &a1_gic.hw,
> +		[CLKID_UART_C]			= &a1_uart_c.hw,
> +		[CLKID_UART_B]			= &a1_uart_b.hw,
> +		[CLKID_UART_A]			= &a1_uart_a.hw,
> +		[CLKID_SYS_PSRAM]		= &a1_sys_psram.hw,
> +		[CLKID_RSA]			= &a1_rsa.hw,
> +		[CLKID_CORESIGHT]		= &a1_coresight.hw,
> +		[CLKID_AM2AXI_VAD]		= &a1_am2axi_vad.hw,
> +		[CLKID_AUDIO_VAD]		= &a1_audio_vad.hw,
> +		[CLKID_AXI_DMC]			= &a1_axi_dmc.hw,
> +		[CLKID_AXI_PSRAM]		= &a1_axi_psram.hw,
> +		[CLKID_RAMB]			= &a1_ramb.hw,
> +		[CLKID_RAMA]			= &a1_rama.hw,
> +		[CLKID_AXI_SPIFC]		= &a1_axi_spifc.hw,
> +		[CLKID_AXI_NIC]			= &a1_axi_nic.hw,
> +		[CLKID_AXI_DMA]			= &a1_axi_dma.hw,
> +		[CLKID_CPU_CTRL]		= &a1_cpu_ctrl.hw,
> +		[CLKID_ROM]			= &a1_rom.hw,
> +		[CLKID_PROC_I2C]		= &a1_prod_i2c.hw,
> +		[CLKID_DSPA_A_SEL]		= &a1_dspa_a_sel.hw,
> +		[CLKID_DSPA_A_DIV]		= &a1_dspa_a_div.hw,
> +		[CLKID_DSPA_A]			= &a1_dspa_a.hw,
> +		[CLKID_DSPA_B_SEL]		= &a1_dspa_b_sel.hw,
> +		[CLKID_DSPA_B_DIV]		= &a1_dspa_b_div.hw,
> +		[CLKID_DSPA_B]			= &a1_dspa_b.hw,
> +		[CLKID_DSPA_SEL]		= &a1_dspa_sel.hw,
> +		[CLKID_DSPB_A_SEL]		= &a1_dspb_a_sel.hw,
> +		[CLKID_DSPB_A_DIV]		= &a1_dspb_a_div.hw,
> +		[CLKID_DSPB_A]			= &a1_dspb_a.hw,
> +		[CLKID_DSPB_B_SEL]		= &a1_dspb_b_sel.hw,
> +		[CLKID_DSPB_B_DIV]		= &a1_dspb_b_div.hw,
> +		[CLKID_DSPB_B]			= &a1_dspb_b.hw,
> +		[CLKID_DSPB_SEL]		= &a1_dspb_sel.hw,
> +		[CLKID_DSPA_EN_DSPA]		= &a1_dspa_en_dspa.hw,
> +		[CLKID_DSPA_EN_NIC]		= &a1_dspa_en_nic.hw,
> +		[CLKID_DSPB_EN_DSPB]		= &a1_dspb_en_dspb.hw,
> +		[CLKID_DSPB_EN_NIC]		= &a1_dspb_en_nic.hw,
> +		[CLKID_24M]			= &a1_24m.hw,
> +		[CLKID_24M_DIV2]		= &a1_24m_div2.hw,
> +		[CLKID_12M]			= &a1_12m.hw,
> +		[CLKID_DIV2_PRE]		= &a1_fclk_div2_divn_pre.hw,
> +		[CLKID_FCLK_DIV2_DIVN]		= &a1_fclk_div2_divn.hw,
> +		[CLKID_GEN_SEL]			= &a1_gen_sel.hw,
> +		[CLKID_GEN_DIV]			= &a1_gen_div.hw,
> +		[CLKID_GEN]			= &a1_gen.hw,
> +		[CLKID_SARADC_SEL]		= &a1_saradc_sel.hw,
> +		[CLKID_SARADC_DIV]		= &a1_saradc_div.hw,
> +		[CLKID_SARADC_CLK]		= &a1_saradc_clk.hw,
> +		[CLKID_PWM_A_SEL]		= &a1_pwm_a_sel.hw,
> +		[CLKID_PWM_A_DIV]		= &a1_pwm_a_div.hw,
> +		[CLKID_PWM_A]			= &a1_pwm_a.hw,
> +		[CLKID_PWM_B_SEL]		= &a1_pwm_b_sel.hw,
> +		[CLKID_PWM_B_DIV]		= &a1_pwm_b_div.hw,
> +		[CLKID_PWM_B]			= &a1_pwm_b.hw,
> +		[CLKID_PWM_C_SEL]		= &a1_pwm_c_sel.hw,
> +		[CLKID_PWM_C_DIV]		= &a1_pwm_c_div.hw,
> +		[CLKID_PWM_C]			= &a1_pwm_c.hw,
> +		[CLKID_PWM_D_SEL]		= &a1_pwm_d_sel.hw,
> +		[CLKID_PWM_D_DIV]		= &a1_pwm_d_div.hw,
> +		[CLKID_PWM_D]			= &a1_pwm_d.hw,
> +		[CLKID_PWM_E_SEL]		= &a1_pwm_e_sel.hw,
> +		[CLKID_PWM_E_DIV]		= &a1_pwm_e_div.hw,
> +		[CLKID_PWM_E]			= &a1_pwm_e.hw,
> +		[CLKID_PWM_F_SEL]		= &a1_pwm_f_sel.hw,
> +		[CLKID_PWM_F_DIV]		= &a1_pwm_f_div.hw,
> +		[CLKID_PWM_F]			= &a1_pwm_f.hw,
> +		[CLKID_SPICC_SEL]		= &a1_spicc_sel.hw,
> +		[CLKID_SPICC_DIV]		= &a1_spicc_div.hw,
> +		[CLKID_SPICC_SEL2]		= &a1_spicc_sel2.hw,
> +		[CLKID_SPICC]			= &a1_spicc.hw,
> +		[CLKID_TS_DIV]			= &a1_ts_div.hw,
> +		[CLKID_TS]			= &a1_ts.hw,
> +		[CLKID_SPIFC_SEL]		= &a1_spifc_sel.hw,
> +		[CLKID_SPIFC_DIV]		= &a1_spifc_div.hw,
> +		[CLKID_SPIFC_SEL2]		= &a1_spifc_sel2.hw,
> +		[CLKID_SPIFC]			= &a1_spifc.hw,
> +		[CLKID_USB_BUS_SEL]		= &a1_usb_bus_sel.hw,
> +		[CLKID_USB_BUS_DIV]		= &a1_usb_bus_div.hw,
> +		[CLKID_USB_BUS]			= &a1_usb_bus.hw,
> +		[CLKID_SD_EMMC_SEL]		= &a1_sd_emmc_sel.hw,
> +		[CLKID_SD_EMMC_DIV]		= &a1_sd_emmc_div.hw,
> +		[CLKID_SD_EMMC_SEL2]		= &a1_sd_emmc_sel2.hw,
> +		[CLKID_SD_EMMC]			= &a1_sd_emmc.hw,
> +		[CLKID_PSRAM_SEL]		= &a1_psram_sel.hw,
> +		[CLKID_PSRAM_DIV]		= &a1_psram_div.hw,
> +		[CLKID_PSRAM_SEL2]		= &a1_psram_sel2.hw,
> +		[CLKID_PSRAM]			= &a1_psram.hw,
> +		[CLKID_DMC_SEL]			= &a1_dmc_sel.hw,
> +		[CLKID_DMC_DIV]			= &a1_dmc_div.hw,
> +		[CLKID_DMC_SEL2]		= &a1_dmc_sel2.hw,
> +		[CLKID_DMC]			= &a1_dmc.hw,
> +		[CLKID_RTC_32K_CLKIN]		= &a1_rtc_32k_clkin.hw,
> +		[CLKID_RTC_32K_DIV]		= &a1_rtc_32k_div.hw,
> +		[CLKID_RTC_32K_XTAL]		= &a1_rtc_32k_xtal.hw,
> +		[CLKID_RTC_32K_SEL]		= &a1_rtc_32k_sel.hw,
> +		[CLKID_RTC_CLK]			= &a1_rtc_clk.hw,
> +		[CLKID_CECA_32K_CLKIN]		= &a1_ceca_32k_clkin.hw,
> +		[CLKID_CECA_32K_DIV]		= &a1_ceca_32k_div.hw,
> +		[CLKID_CECA_32K_SEL_PRE]	= &a1_ceca_32k_sel_pre.hw,
> +		[CLKID_CECA_32K_SEL]		= &a1_ceca_32k_sel.hw,
> +		[CLKID_CECA_32K]		= &a1_ceca_32k_clkout.hw,
> +		[CLKID_CECB_32K_CLKIN]		= &a1_cecb_32k_clkin.hw,
> +		[CLKID_CECB_32K_DIV]		= &a1_cecb_32k_div.hw,
> +		[CLKID_CECB_32K_SEL_PRE]	= &a1_cecb_32k_sel_pre.hw,
> +		[CLKID_CECB_32K_SEL]		= &a1_cecb_32k_sel.hw,
> +		[CLKID_CECB_32K]		= &a1_cecb_32k_clkout.hw,
> +		[NR_CLKS]			= NULL,
> +	},
> +	.num = NR_CLKS,
> +};
> +
> +/* Convenience table to populate regmap in .probe */
> +static struct clk_regmap *const a1_periphs_regmaps[] = {
> +	&a1_xtal_clktree,
> +	&a1_xtal_fixpll,
> +	&a1_xtal_usb_phy,
> +	&a1_xtal_usb_ctrl,
> +	&a1_xtal_hifipll,
> +	&a1_xtal_syspll,
> +	&a1_xtal_dds,
> +	&a1_clk_tree,
> +	&a1_reset_ctrl,
> +	&a1_analog_ctrl,
> +	&a1_pwr_ctrl,
> +	&a1_sys_ctrl,
> +	&a1_temp_sensor,
> +	&a1_am2axi_dev,
> +	&a1_spicc_b,
> +	&a1_spicc_a,
> +	&a1_clk_msr,
> +	&a1_audio,
> +	&a1_jtag_ctrl,
> +	&a1_saradc,
> +	&a1_pwm_ef,
> +	&a1_pwm_cd,
> +	&a1_pwm_ab,
> +	&a1_cec,
> +	&a1_i2c_s,
> +	&a1_ir_ctrl,
> +	&a1_i2c_m_d,
> +	&a1_i2c_m_c,
> +	&a1_i2c_m_b,
> +	&a1_i2c_m_a,
> +	&a1_acodec,
> +	&a1_otp,
> +	&a1_sd_emmc_a,
> +	&a1_usb_phy,
> +	&a1_usb_ctrl,
> +	&a1_sys_dspb,
> +	&a1_sys_dspa,
> +	&a1_dma,
> +	&a1_irq_ctrl,
> +	&a1_nic,
> +	&a1_gic,
> +	&a1_uart_c,
> +	&a1_uart_b,
> +	&a1_uart_a,
> +	&a1_sys_psram,
> +	&a1_rsa,
> +	&a1_coresight,
> +	&a1_am2axi_vad,
> +	&a1_audio_vad,
> +	&a1_axi_dmc,
> +	&a1_axi_psram,
> +	&a1_ramb,
> +	&a1_rama,
> +	&a1_axi_spifc,
> +	&a1_axi_nic,
> +	&a1_axi_dma,
> +	&a1_cpu_ctrl,
> +	&a1_rom,
> +	&a1_prod_i2c,
> +	&a1_dspa_a_sel,
> +	&a1_dspa_a_div,
> +	&a1_dspa_a,
> +	&a1_dspa_b_sel,
> +	&a1_dspa_b_div,
> +	&a1_dspa_b,
> +	&a1_dspa_sel,
> +	&a1_dspb_a_sel,
> +	&a1_dspb_a_div,
> +	&a1_dspb_a,
> +	&a1_dspb_b_sel,
> +	&a1_dspb_b_div,
> +	&a1_dspb_b,
> +	&a1_dspb_sel,
> +	&a1_dspa_en_dspa,
> +	&a1_dspa_en_nic,
> +	&a1_dspb_en_dspb,
> +	&a1_dspb_en_nic,
> +	&a1_24m,
> +	&a1_12m,
> +	&a1_fclk_div2_divn_pre,
> +	&a1_fclk_div2_divn,
> +	&a1_gen_sel,
> +	&a1_gen_div,
> +	&a1_gen,
> +	&a1_saradc_sel,
> +	&a1_saradc_div,
> +	&a1_saradc_clk,
> +	&a1_pwm_a_sel,
> +	&a1_pwm_a_div,
> +	&a1_pwm_a,
> +	&a1_pwm_b_sel,
> +	&a1_pwm_b_div,
> +	&a1_pwm_b,
> +	&a1_pwm_c_sel,
> +	&a1_pwm_c_div,
> +	&a1_pwm_c,
> +	&a1_pwm_d_sel,
> +	&a1_pwm_d_div,
> +	&a1_pwm_d,
> +	&a1_pwm_e_sel,
> +	&a1_pwm_e_div,
> +	&a1_pwm_e,
> +	&a1_pwm_f_sel,
> +	&a1_pwm_f_div,
> +	&a1_pwm_f,
> +	&a1_spicc_sel,
> +	&a1_spicc_div,
> +	&a1_spicc_sel2,
> +	&a1_spicc,
> +	&a1_ts_div,
> +	&a1_ts,
> +	&a1_spifc_sel,
> +	&a1_spifc_div,
> +	&a1_spifc_sel2,
> +	&a1_spifc,
> +	&a1_usb_bus_sel,
> +	&a1_usb_bus_div,
> +	&a1_usb_bus,
> +	&a1_sd_emmc_sel,
> +	&a1_sd_emmc_div,
> +	&a1_sd_emmc_sel2,
> +	&a1_sd_emmc,
> +	&a1_psram_sel,
> +	&a1_psram_div,
> +	&a1_psram_sel2,
> +	&a1_psram,
> +	&a1_dmc_sel,
> +	&a1_dmc_div,
> +	&a1_dmc_sel2,
> +	&a1_dmc,
> +	&a1_sys_b_sel,
> +	&a1_sys_b_div,
> +	&a1_sys_b,
> +	&a1_sys_a_sel,
> +	&a1_sys_a_div,
> +	&a1_sys_a,
> +	&a1_sys_clk,
> +	&a1_rtc_32k_clkin,
> +	&a1_rtc_32k_div,
> +	&a1_rtc_32k_xtal,
> +	&a1_rtc_32k_sel,
> +	&a1_rtc_clk,
> +	&a1_ceca_32k_clkin,
> +	&a1_ceca_32k_div,
> +	&a1_ceca_32k_sel_pre,
> +	&a1_ceca_32k_sel,
> +	&a1_ceca_32k_clkout,
> +	&a1_cecb_32k_clkin,
> +	&a1_cecb_32k_div,
> +	&a1_cecb_32k_sel_pre,
> +	&a1_cecb_32k_sel,
> +	&a1_cecb_32k_clkout,
> +};
> +
> +static int meson_a1_periphs_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +
> +	ret = meson_eeclkc_probe(pdev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}

Again this function is function is useless and it makes me wonder if you
should really be using meson_eeclkc_probe()

This makes you use syscon which is not correct unless you have a good
reason ?

Is there anything but clocks and resets in these register region ?

> +
> +static const struct meson_eeclkc_data a1_periphs_data = {
> +		.regmap_clks = a1_periphs_regmaps,
> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
> +};
> +static const struct of_device_id clkc_match_table[] = {
> +	{
> +		.compatible = "amlogic,a1-periphs-clkc",
> +		.data = &a1_periphs_data
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver a1_driver = {
> +	.probe		= meson_a1_periphs_probe,
> +	.driver		= {
> +		.name	= "a1-periphs-clkc",
> +		.of_match_table = clkc_match_table,
> +	},
> +};
> +
> +builtin_platform_driver(a1_driver);
> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
> new file mode 100644
> index 0000000..1ae5e04
> --- /dev/null
> +++ b/drivers/clk/meson/a1.h
> @@ -0,0 +1,120 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#ifndef __A1_H
> +#define __A1_H
> +
> +/* peripheral clock controller register offset */
> +#define SYS_OSCIN_CTRL			0x0
> +#define RTC_BY_OSCIN_CTRL0		0x4
> +#define RTC_BY_OSCIN_CTRL1		0x8
> +#define RTC_CTRL			0xc
> +#define SYS_CLK_CTRL0			0x10
> +#define AXI_CLK_CTRL0			0x14
> +#define SYS_CLK_EN0			0x1c
> +#define SYS_CLK_EN1			0x20
> +#define AXI_CLK_EN			0x24
> +#define DSPA_CLK_EN			0x28
> +#define DSPB_CLK_EN			0x2c
> +#define DSPA_CLK_CTRL0			0x30
> +#define DSPB_CLK_CTRL0			0x34
> +#define CLK12_24_CTRL			0x38
> +#define GEN_CLK_CTRL			0x3c
> +#define TIMESTAMP_CTRL0			0x40
> +#define TIMESTAMP_CTRL1			0x44
> +#define TIMESTAMP_CTRL2			0x48
> +#define TIMESTAMP_VAL0			0x4c
> +#define TIMESTAMP_VAL1			0x50
> +#define TIMEBASE_CTRL0			0x54
> +#define TIMEBASE_CTRL1			0x58
> +#define SAR_ADC_CLK_CTRL		0xc0
> +#define PWM_CLK_AB_CTRL			0xc4
> +#define PWM_CLK_CD_CTRL			0xc8
> +#define PWM_CLK_EF_CTRL			0xcc
> +#define SPICC_CLK_CTRL			0xd0
> +#define TS_CLK_CTRL			0xd4
> +#define SPIFC_CLK_CTRL			0xd8
> +#define USB_BUSCLK_CTRL			0xdc
> +#define SD_EMMC_CLK_CTRL		0xe0
> +#define CECA_CLK_CTRL0			0xe4
> +#define CECA_CLK_CTRL1			0xe8
> +#define CECB_CLK_CTRL0			0xec
> +#define CECB_CLK_CTRL1			0xf0
> +#define PSRAM_CLK_CTRL			0xf4
> +#define DMC_CLK_CTRL			0xf8
> +#define FCLK_DIV1_SEL			0xfc
> +#define TST_CTRL			0x100
> +
> +#define CLKID_XTAL_CLKTREE		0
> +#define CLKID_SYS_A_SEL			89
> +#define CLKID_SYS_A_DIV			90
> +#define CLKID_SYS_A			91
> +#define CLKID_SYS_B_SEL			92
> +#define CLKID_SYS_B_DIV			93
> +#define CLKID_SYS_B			94
> +#define CLKID_DSPA_A_SEL		95
> +#define CLKID_DSPA_A_DIV		96
> +#define CLKID_DSPA_A			97
> +#define CLKID_DSPA_B_SEL		98
> +#define CLKID_DSPA_B_DIV		99
> +#define CLKID_DSPA_B			100
> +#define CLKID_DSPB_A_SEL		101
> +#define CLKID_DSPB_A_DIV		102
> +#define CLKID_DSPB_A			103
> +#define CLKID_DSPB_B_SEL		104
> +#define CLKID_DSPB_B_DIV		105
> +#define CLKID_DSPB_B			106
> +#define CLKID_RTC_32K_CLKIN		107
> +#define CLKID_RTC_32K_DIV		108
> +#define CLKID_RTC_32K_XTAL		109
> +#define CLKID_RTC_32K_SEL		110
> +#define CLKID_CECB_32K_CLKIN		111
> +#define CLKID_CECB_32K_DIV		112
> +#define CLKID_CECB_32K_SEL_PRE		113
> +#define CLKID_CECB_32K_SEL		114
> +#define CLKID_CECA_32K_CLKIN		115
> +#define CLKID_CECA_32K_DIV		116
> +#define CLKID_CECA_32K_SEL_PRE		117
> +#define CLKID_CECA_32K_SEL		118
> +#define CLKID_DIV2_PRE			119
> +#define CLKID_24M_DIV2			120
> +#define CLKID_GEN_SEL			121
> +#define CLKID_GEN_DIV			122
> +#define CLKID_SARADC_DIV		123
> +#define CLKID_PWM_A_SEL			124
> +#define CLKID_PWM_A_DIV			125
> +#define CLKID_PWM_B_SEL			126
> +#define CLKID_PWM_B_DIV			127
> +#define CLKID_PWM_C_SEL			128
> +#define CLKID_PWM_C_DIV			129
> +#define CLKID_PWM_D_SEL			130
> +#define CLKID_PWM_D_DIV			131
> +#define CLKID_PWM_E_SEL			132
> +#define CLKID_PWM_E_DIV			133
> +#define CLKID_PWM_F_SEL			134
> +#define CLKID_PWM_F_DIV			135
> +#define CLKID_SPICC_SEL			136
> +#define CLKID_SPICC_DIV			137
> +#define CLKID_SPICC_SEL2		138
> +#define CLKID_TS_DIV			139
> +#define CLKID_SPIFC_SEL			140
> +#define CLKID_SPIFC_DIV			141
> +#define CLKID_SPIFC_SEL2		142
> +#define CLKID_USB_BUS_SEL		143
> +#define CLKID_USB_BUS_DIV		144
> +#define CLKID_SD_EMMC_SEL		145
> +#define CLKID_SD_EMMC_DIV		146
> +#define CLKID_SD_EMMC_SEL2		147
> +#define CLKID_PSRAM_SEL			148
> +#define CLKID_PSRAM_DIV			149
> +#define CLKID_PSRAM_SEL2		150
> +#define CLKID_DMC_SEL			151
> +#define CLKID_DMC_DIV			152
> +#define CLKID_DMC_SEL2			153
> +#define NR_CLKS				154
> +
> +#include <dt-bindings/clock/a1-clkc.h>
> +
> +#endif /* __A1_H */


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

* Re: [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-10-21 10:43   ` Jerome Brunet
@ 2019-10-22  5:30     ` Jian Hu
  0 siblings, 0 replies; 22+ messages in thread
From: Jian Hu @ 2019-10-22  5:30 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

Hi, Jerome

Thanks for your review.

On 2019/10/21 18:43, Jerome Brunet wrote:
> 
> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Add the documentation to support Amlogic A1 clock driver,
>> and add A1 clock controller bindings.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> ---
>>   .../devicetree/bindings/clock/amlogic,a1-clkc.yaml | 143
>> +++++++++++++++++++++
> 
> Those are 2 different controllers, not variants.
> One description (one file) per controller please
OK, I will describe for periphs and PLLs controller separately.
> 
>>   include/dt-bindings/clock/a1-clkc.h                |  98 ++++++++++++++
>>   include/dt-bindings/clock/a1-pll-clkc.h            |  16 +++
>>   3 files changed, 257 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>>   create mode 100644 include/dt-bindings/clock/a1-clkc.h
>>   create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>> new file mode 100644
>> index 0000000..b382eebe
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>> @@ -0,0 +1,143 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +%YAML 1.2
>> +---
>> +$id: "http://devicetree.org/schemas/clock/amlogic,a1-clkc.yaml#"
>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>> +
>> +title: Amlogic Meson A/C serials Clock Control Unit Device Tree Bindings
>> +
>> +maintainers:
>> +  - Neil Armstrong <narmstrong@baylibre.com>
>> +  - Jerome Brunet <jbrunet@baylibre.com>
>> +  - Jian Hu <jian.hu@jian.hu.com>
>> +
>> +description: |+
>> +  The clock controller node should be the child of a syscon node with the
>> +  required property:
>> +
>> +  - compatible:         Should be one of the following:
>> +                        "amlogic,meson-a-analog-sysctrl", "syscon", "simple-mfd"
>> +                        "amlogic,meson-a-periphs-sysctrl", "syscon", "simple-mfd"
>> +
>> +  Refer to the the bindings described in
>> +  Documentation/devicetree/bindings/mfd/syscon.txt
>> +
>> +properties:
>> +  "#clock-cells":
>> +    const: 1
>> +  compatible:
>> +    - enum:
>> +        - amlogic,a1-periphs-clkc
>> +        - amlogic,a1-pll-clkc
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    minItems: 2
>> +    maxItems: 6
>> +
>> +  clock-names:
>> +    minItems: 2
>> +    maxItems: 6
>> +
>> +required:
>> +  - "#clock-cells"
>> +  - compatible
>> +  - reg
>> +  - clocks
>> +  - clock-names
>> +
>> +if:
>> +  properties:
>> +    compatible:
>> +      enum:
>> +        - amlogic,a1-periphs-clkc
>> +
>> +then:
>> +  properties:
>> +    clocks:
>> +      minItems: 2
>> +      maxItems: 2
>> +    items:
>> +     - description: fixed pll gate clock
>> +     - description: hifi pll gate clock
>> +
>> +    clock-names:
>> +      minItems: 2
>> +      maxItems: 2
>> +      items:
>> +        - const: xtal_fixpll
>> +        - const: xtal_hifipll
>> +
>> +else:
>> +  if:
>> +    properties:
>> +      compatible:
>> +        const: amlogic,a1-pll-clkc
>> +
>> +  then:
>> +    properties:
>> +      clocks:
>> +        minItems: 6
>> +        maxItems: 6
>> +        items:
>> +         - description: Input fixed pll div2
>> +         - description: Input fixed pll div3
>> +         - description: Input fixed pll div5
>> +         - description: Input fixed pll div7
>> +         - description: Periph Hifi pll
>> +         - description: Input Oscillator (usually at 24MHz)
>> +
>> +      clock-names:
>> +        minItems: 6
>> +        maxItems: 6
>> +        items:
>> +         - const: fclk_div2
>> +         - const: fclk_div3
>> +         - const: fclk_div5
>> +         - const: fclk_div7
>> +         - const: hifi_pll
>> +         - const: xtal
>> +
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    analog: system-controller@0 {
>> +        compatible = "amlogic,meson-a-analog-sysctrl",
>> +                     "simple-mfd", "syscon";
>> +        reg = <0 0x7c00 0 0x21c>;
>> +
>> +        clkc_pll: pll-clock-controller {
>> +                compatible = "amlogic,a1-pll-clkc";
>> +                #clock-cells = <1>;
>> +                clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
>> +                         <&clkc_periphs CLKID_XTAL_HIFIPLL>;
>> +                clock-names = "xtal_fixpll", "xtal_hifipll";
>> +        };
>> +    };
>> +
>> +  - |
>> +    periphs: system-controller@1 {
>> +        compatible = "amlogic,meson-a-periphs-sysctrl",
>> +                     "simple-mfd", "syscon";
>> +        reg = <0 0x800 0 0x104>;
>> +
>> +        clkc_periphs: periphs-clock-controller {
>> +                compatible = "amlogic,a1-periphs-clkc";
>> +                #clock-cells = <1>;
>> +                clocks = <&clkc_pll CLKID_FCLK_DIV2>,
>> +                        <&clkc_pll CLKID_FCLK_DIV3>,
>> +                        <&clkc_pll CLKID_FCLK_DIV5>,
>> +                        <&clkc_pll CLKID_FCLK_DIV7>,
>> +                        <&clkc_pll CLKID_HIFI_PLL>,
>> +                        <&xtal>;
>> +                clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
>> +                              "fclk_div7", "hifi_pll", "xtal";
>> +        };
>> +    };
>> diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h
>> new file mode 100644
>> index 0000000..1ba0112
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/a1-clkc.h
>> @@ -0,0 +1,98 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __A1_CLKC_H
>> +#define __A1_CLKC_H
>> +
>> +#define CLKID_XTAL_FIXPLL			1
>> +#define CLKID_XTAL_USB_PHY			2
>> +#define CLKID_XTAL_USB_CTRL			3
>> +#define CLKID_XTAL_HIFIPLL			4
>> +#define CLKID_XTAL_SYSPLL			5
>> +#define CLKID_XTAL_DDS				6
>> +#define CLKID_SYS_CLK				7
>> +#define CLKID_CLKTREE				8
>> +#define CLKID_RESET_CTRL			9
>> +#define CLKID_ANALOG_CTRL			10
>> +#define CLKID_PWR_CTRL				11
>> +#define CLKID_PAD_CTRL				12
>> +#define CLKID_SYS_CTRL				13
>> +#define CLKID_TEMP_SENSOR			14
>> +#define CLKID_AM2AXI_DIV			15
>> +#define CLKID_SPICC_B				16
>> +#define CLKID_SPICC_A				17
>> +#define CLKID_CLK_MSR				18
>> +#define CLKID_AUDIO				19
>> +#define CLKID_JTAG_CTRL				20
>> +#define CLKID_SARADC				21
>> +#define CLKID_PWM_EF				22
>> +#define CLKID_PWM_CD				23
>> +#define CLKID_PWM_AB				24
>> +#define CLKID_CEC				25
>> +#define CLKID_I2C_S				26
>> +#define CLKID_IR_CTRL				27
>> +#define CLKID_I2C_M_D				28
>> +#define CLKID_I2C_M_C				29
>> +#define CLKID_I2C_M_B				30
>> +#define CLKID_I2C_M_A				31
>> +#define CLKID_ACODEC				32
>> +#define CLKID_OTP				33
>> +#define CLKID_SD_EMMC_A				34
>> +#define CLKID_USB_PHY				35
>> +#define CLKID_USB_CTRL				36
>> +#define CLKID_SYS_DSPB				37
>> +#define CLKID_SYS_DSPA				38
>> +#define CLKID_DMA				39
>> +#define CLKID_IRQ_CTRL				40
>> +#define CLKID_NIC				41
>> +#define CLKID_GIC				42
>> +#define CLKID_UART_C				43
>> +#define CLKID_UART_B				44
>> +#define CLKID_UART_A				45
>> +#define CLKID_SYS_PSRAM				46
>> +#define CLKID_RSA				47
>> +#define CLKID_CORESIGHT				48
>> +#define CLKID_AM2AXI_VAD			49
>> +#define CLKID_AUDIO_VAD				50
>> +#define CLKID_AXI_DMC				51
>> +#define CLKID_AXI_PSRAM				52
>> +#define CLKID_RAMB				53
>> +#define CLKID_RAMA				54
>> +#define CLKID_AXI_SPIFC				55
>> +#define CLKID_AXI_NIC				56
>> +#define CLKID_AXI_DMA				57
>> +#define CLKID_CPU_CTRL				58
>> +#define CLKID_ROM				59
>> +#define CLKID_PROC_I2C				60
>> +#define CLKID_DSPA_SEL				61
>> +#define CLKID_DSPB_SEL				62
>> +#define CLKID_DSPA_EN_DSPA			63
>> +#define CLKID_DSPA_EN_NIC			64
>> +#define CLKID_DSPB_EN_DSPB			65
>> +#define CLKID_DSPB_EN_NIC			66
>> +#define CLKID_RTC_CLK				67
>> +#define CLKID_CECA_32K				68
>> +#define CLKID_CECB_32K				69
>> +#define CLKID_24M				70
>> +#define CLKID_12M				71
>> +#define CLKID_FCLK_DIV2_DIVN			72
>> +#define CLKID_GEN				73
>> +#define CLKID_SARADC_SEL			74
>> +#define CLKID_SARADC_CLK			75
>> +#define CLKID_PWM_A				76
>> +#define CLKID_PWM_B				77
>> +#define CLKID_PWM_C				78
>> +#define CLKID_PWM_D				79
>> +#define CLKID_PWM_E				80
>> +#define CLKID_PWM_F				81
>> +#define CLKID_SPICC				82
>> +#define CLKID_TS				83
>> +#define CLKID_SPIFC				84
>> +#define CLKID_USB_BUS				85
>> +#define CLKID_SD_EMMC				86
>> +#define CLKID_PSRAM				87
>> +#define CLKID_DMC				88
>> +
>> +#endif /* __A1_CLKC_H */
>> diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
>> new file mode 100644
>> index 0000000..58eae23
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/a1-pll-clkc.h
>> @@ -0,0 +1,16 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __A1_PLL_CLKC_H
>> +#define __A1_PLL_CLKC_H
>> +
>> +#define CLKID_FIXED_PLL				1
>> +#define CLKID_FCLK_DIV2				6
>> +#define CLKID_FCLK_DIV3				7
>> +#define CLKID_FCLK_DIV5				8
>> +#define CLKID_FCLK_DIV7				9
>> +#define CLKID_HIFI_PLL				10
>> +
>> +#endif /* __A1_PLL_CLKC_H */
> 
> .
> 

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

* Re: [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops
  2019-10-21 11:31   ` Jerome Brunet
@ 2019-10-25  6:47     ` Jian Hu
  0 siblings, 0 replies; 22+ messages in thread
From: Jian Hu @ 2019-10-25  6:47 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

Hi, Jerome

On 2019/10/21 19:31, Jerome Brunet wrote:
> 
> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> The A1 PLL design is different with previous SoCs. The PLL
>> internal analog modules Power-on sequence is different
>> with previous, and thus requires a strict register sequence to
>> enable the PLL. Unlike the previous series, the maximum frequency
>> is 6G in G12A, for A1 the maximum is 1536M.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> ---
>>   drivers/clk/meson/clk-pll.c | 66 ++++++++++++++++++++++++++++++++++++++++-----
>>   drivers/clk/meson/clk-pll.h |  1 +
>>   2 files changed, 61 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
>> index ddb1e56..b440e62 100644
>> --- a/drivers/clk/meson/clk-pll.c
>> +++ b/drivers/clk/meson/clk-pll.c
>> @@ -349,6 +349,56 @@ static void meson_clk_pll_disable(struct clk_hw *hw)
>>   	meson_parm_write(clk->map, &pll->en, 0);
>>   }
>>   
>> +/*
>> + * The A1 design is different with previous SoCs.The PLL
>> + * internal analog modules Power-on sequence is different with
>> + * previous, different PLL has the different sequence, and
>> + * thus requires a strict register sequence to enable the PLL.
>> + * When set a new target frequency, the sequence should keep
>> + * the same with the initial sequence. Unlike the previous series,
>> + * the maximum frequency is 6G in G12A, for A1 the maximum
>> + * is 1536M.
> 
> The comment about the max frequency belongs in your a1 driver, not in
> the PLL driver
> 
OK, I will remove the max frequency comments
>> + */
>> +static void meson_params_update_with_init_seq(struct clk_regmap *clk,
>> +				       struct meson_clk_pll_data *pll,
>> +				       unsigned int m, unsigned int n,
>> +				       unsigned int frac)
>> +{
>> +	struct parm *pm = &pll->m;
>> +	struct parm *pn = &pll->n;
>> +	struct parm *pfrac = &pll->frac;
>> +	const struct reg_sequence *init_regs = pll->init_regs;
>> +	unsigned int i, val;
>> +
>> +	for (i = 0; i < pll->init_count; i++) {
>> +		if (pn->reg_off == init_regs[i].reg) {
>> +			/* Clear M N bits and Update M N value */
>> +			val = init_regs[i].def;
>> +			val &= CLRPMASK(pn->width, pn->shift);
>> +			val &= CLRPMASK(pm->width, pm->shift);
>> +			val |= n << pn->shift;
>> +			val |= m << pm->shift;
>> +			regmap_write(clk->map, pn->reg_off, val);
>> +		} else if (MESON_PARM_APPLICABLE(&pll->frac) &&
>> +			   (pfrac->reg_off == init_regs[i].reg)) {
>> +			/* Clear Frac bits and Update Frac value */
>> +			val = init_regs[i].def;
>> +			val &= CLRPMASK(pfrac->width, pfrac->shift);
>> +			val |= frac << pfrac->shift;
>> +			regmap_write(clk->map, pfrac->reg_off, val);
>> +		} else {
>> +			/*
>> +			 * According to the PLL hardware constraint,
>> +			 * the left registers should be setted again.
>> +			 */
>> +			val = init_regs[i].def;
>> +			regmap_write(clk->map, init_regs[i].reg, val);
>> +		}
>> +		if (init_regs[i].delay_us)
>> +			udelay(init_regs[i].delay_us);
>> +	}
> 
> So:
> 
> 1) All the code above this there make the PLL lock, IOW enable the
> PLL. It does not belong in the set_rate() callback but in enable() or
> prepare() maybe.
> 
> 2) All the above is works but it is a bit over complicated for what it
> does. From the a1_hifi_init_regs I see, all you really need to do is
>    * toggle BIT(6) in CTRL2
>    * toggle BIT(28) in CTRL0 (enable PARM)
>    * toggle BIT(26) in CTRL0
> 
> You could use PARM 'rst' for one them and introduce another parm for the
> other one. You would not need to repoke the whole sequence this way.
> 
OK, I have realized as you suggested. I will send it in the V3 patch.
>> +}
>> +
>>   static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>>   				  unsigned long parent_rate)
>>   {
>> @@ -366,16 +416,20 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>>   	if (ret)
>>   		return ret;
>>   
>> +	if (MESON_PARM_APPLICABLE(&pll->frac))
>> +		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
>> +
>>   	enabled = meson_parm_read(clk->map, &pll->en);
>>   	if (enabled)
>>   		meson_clk_pll_disable(hw);
>>   
>> -	meson_parm_write(clk->map, &pll->n, n);
>> -	meson_parm_write(clk->map, &pll->m, m);
>> -
>> -	if (MESON_PARM_APPLICABLE(&pll->frac)) {
>> -		frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
>> -		meson_parm_write(clk->map, &pll->frac, frac);
>> +	if (pll->strict_sequence)
>> +		meson_params_update_with_init_seq(clk, pll, m, n, frac);
>> +	else {
>> +		meson_parm_write(clk->map, &pll->n, n);
>> +		meson_parm_write(clk->map, &pll->m, m);
>> +		if (MESON_PARM_APPLICABLE(&pll->frac))
>> +			meson_parm_write(clk->map, &pll->frac, frac);
>>   	}
>>   
>>   	/* If the pll is stopped, bail out now */
>> diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h
>> index 367efd0..d5789cef 100644
>> --- a/drivers/clk/meson/clk-pll.h
>> +++ b/drivers/clk/meson/clk-pll.h
>> @@ -41,6 +41,7 @@ struct meson_clk_pll_data {
>>   	const struct pll_params_table *table;
>>   	const struct pll_mult_range *range;
>>   	u8 flags;
>> +	bool strict_sequence;
> 
> Don't introduce parameter for this We have ops to tune the behavior of
> the clock driver. Properly refactor the code if some of it is common.
> 
remove the strict_sequence.
>>   };
>>   
>>   extern const struct clk_ops meson_clk_pll_ro_ops;
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-21 11:41   ` Jerome Brunet
@ 2019-10-25 11:32     ` Jian Hu
  2019-11-04  8:24       ` Jerome Brunet
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-10-25 11:32 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel

Hi, Jerome

Thanks for your review

On 2019/10/21 19:41, Jerome Brunet wrote:
> 
> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> The Amlogic A1 clock includes three drivers:
>> peripheral clocks, pll clocks, CPU clocks.
>> sys pll and CPU clocks will be sent in next patch.
>>
>> Unlike the previous series, there is no EE/AO domain
>> in A1 CLK controllers.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> ---
>>   drivers/clk/meson/Kconfig  |   10 +
>>   drivers/clk/meson/Makefile |    1 +
>>   drivers/clk/meson/a1-pll.c |  345 +++++++
>>   drivers/clk/meson/a1-pll.h |   56 ++
>>   drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/meson/a1.h     |  120 +++
>>   6 files changed, 2796 insertions(+)
>>   create mode 100644 drivers/clk/meson/a1-pll.c
>>   create mode 100644 drivers/clk/meson/a1-pll.h
>>   create mode 100644 drivers/clk/meson/a1.c
>>   create mode 100644 drivers/clk/meson/a1.h
> 
> In the next version, one
OK, I will send a1 peripheral and pll driver in two patch.
> 
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index dabeb43..c2809b2 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>   	  Support for the audio clock controller on AmLogic A113D devices,
>>   	  aka axg, Say Y if you want audio subsystem to work.
>>   
>> +config COMMON_CLK_A1
>> +	bool
>> +	depends on ARCH_MESON
>> +	select COMMON_CLK_MESON_REGMAP
>> +	select COMMON_CLK_MESON_DUALDIV
>> +	select COMMON_CLK_MESON_PLL
>> +	help
>> +	  Support for the clock controller on Amlogic A113L device,
>> +	  aka a1. Say Y if you want peripherals to work.
>> +
>>   config COMMON_CLK_G12A
>>   	bool
>>   	depends on ARCH_MESON
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 3939f21..28cbae1 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>>   
>>   obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>   obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
> 
> So far, all the controller had there own option, I don't see why it
> should be different here.
> 
OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll driver
>>   obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>   obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>   obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>> new file mode 100644
>> index 0000000..486d964
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1-pll.c
>> @@ -0,0 +1,345 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + * Author: Jian Hu <jian.hu@amlogic.com>
>> + */
>> +
>> +#include <linux/platform_device.h>
> 
> Hum ... looks like some things are missing here
> 
> #include <linux/of_device.h>
> #include <linux/clk-provider.h>
> 
> ?
#1
There is <linux/clk-provider.h> in meson-eeclk.h file,

and for A1 driver(a1.c/a1-pll.c) the head file is not requied.

#2
For A1 driver, the file "linux/of_device.h" is not required.
It is required by meson-eeclk.c in fact.
> 
>> +#include "clk-pll.h"
>> +#include "meson-eeclk.h"
>> +#include "a1-pll.h"
> 
> Alphanumeric order please
>
OK, I will change it in the next version.

>> +
>> +static struct clk_regmap a1_fixed_pll_dco = {
>> +	.data = &(struct meson_clk_pll_data){
>> +		.en = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>> +			.shift   = 28,
>> +			.width   = 1,
>> +		},
>> +		.m = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>> +			.shift   = 0,
>> +			.width   = 8,
>> +		},
>> +		.n = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>> +			.shift   = 10,
>> +			.width   = 5,
>> +		},
>> +		.frac = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
>> +			.shift   = 0,
>> +			.width   = 19,
>> +		},
>> +		.l = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>> +			.shift   = 31,
>> +			.width   = 1,
>> +		},
>> +		.rst = {
>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>> +			.shift   = 29,
>> +			.width   = 1,
>> +		},
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fixed_pll_dco",
>> +		.ops = &meson_clk_pll_ro_ops,
>> +		.parent_data = &(const struct clk_parent_data){
>> +			.fw_name = "xtal_fixpll",
>> +			.name = "xtal_fixpll",
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_fixed_pll = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>> +		.bit_idx = 20,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "fixed_pll",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fixed_pll_dco.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * This clock is fclk_div2/3/4's parent,
>> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
> 
> is it fclk_div2/3/4 or fclk_div2/3/5 ?
> 
>> +		 * It is required by the platform to operate correctly.
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
> 
> Don't blindly copy/paste comments from other drivers. There is no driver
> for the devices you are mentionning so the end of the comment is
> confusing. The 3 first lines were enough
> 
OK, I will remove the confusing comments

>> +		.flags = CLK_IS_CRITICAL,
> 
>>From your comment, I understand that some child are critical, not this
> particular (or at least, not directly). So this can be removed AFAICT
> 
> You should even need CLK_IGNORE_UNUSED for this one since the clock will
> already be enabled before the late_init() kicks in
> 
OK, I will replace it as CLK_IGNORE_UNUSED.
>> +	},
>> +};
>> +
>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>> +	.min = 32,
>> +	.max = 64,
>> +};
>> +
>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>> +};
>> +
>> +static struct clk_regmap a1_hifi_pll = {
>> +	.data = &(struct meson_clk_pll_data){
>> +		.en = {
>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>> +			.shift   = 28,
>> +			.width   = 1,
>> +		},
>> +		.m = {
>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>> +			.shift   = 0,
>> +			.width   = 8,
>> +		},
>> +		.n = {
>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>> +			.shift   = 10,
>> +			.width   = 5,
>> +		},
>> +		.frac = {
>> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
>> +			.shift   = 0,
>> +			.width   = 19,
>> +		},
>> +		.l = {
>> +			.reg_off = ANACTRL_HIFIPLL_STS,
>> +			.shift   = 31,
>> +			.width   = 1,
>> +		},
>> +		.range = &a1_hifi_pll_mult_range,
>> +		.init_regs = a1_hifi_init_regs,
>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>> +		.strict_sequence = true,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "hifi_pll",
>> +		.ops = &meson_clk_pll_ops,
>> +		.parent_data = &(const struct clk_parent_data){
>> +			.fw_name = "xtal_fixpll",
>> +			.name = "xtal_fixpll",
> 
> Both should provided when a controller transition from the old way of
> describing parent to the new way. This is a new controller so it does
> not apply.
I do not understand why it does not apply, could you explain more?

The xtal_fixpll clock is registered in another peripheral driver, If do 
not desribe the "name" member in parent_data, "fw_name" does not work 
because it has not been registered. the hifi_pll parent will be null in 
/sys/kernel/debug/clk/hifi_pll/clk_parent.

HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.

So both of "fw_name" of "name" should be described.

> 
> Same for the other occurences.
> 
> Also, I think you meant xtal_hifipll
Yes,I will correct it.
> 
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>> +	.mult = 1,
>> +	.div = 2,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div2_div",
>> +		.ops = &clk_fixed_factor_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fixed_pll.hw
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_fclk_div2 = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>> +		.bit_idx = 21,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div2",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fclk_div2_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * This clock is used by DDR clock in BL2 firmware
>> +		 * and is required by the platform to operate correctly.
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>> +	.mult = 1,
>> +	.div = 3,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div3_div",
>> +		.ops = &clk_fixed_factor_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fixed_pll.hw
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_fclk_div3 = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>> +		.bit_idx = 22,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div3",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fclk_div3_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * This clock is used by APB bus which setted in Romcode
>> +		 * and is required by the platform to operate correctly.
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>> +	.mult = 1,
>> +	.div = 5,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div5_div",
>> +		.ops = &clk_fixed_factor_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fixed_pll.hw
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_fclk_div5 = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>> +		.bit_idx = 23,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div5",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fclk_div5_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * This clock is used by AXI bus which setted in Romcode
>> +		 * and is required by the platform to operate correctly.
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>> +	.mult = 1,
>> +	.div = 7,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div7_div",
>> +		.ops = &clk_fixed_factor_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fixed_pll.hw
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_fclk_div7 = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>> +		.bit_idx = 24,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "fclk_div7",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_fclk_div7_div.hw
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +
>> +/* Array of all clocks provided by this provider */
>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>> +	.hws = {
>> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
>> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
>> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
>> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
>> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
>> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
>> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
>> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
>> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
>> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
>> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
>> +		[NR_PLL_CLKS]			= NULL,
>> +	},
>> +	.num = NR_PLL_CLKS,
>> +};
>> +
>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>> +	&a1_fixed_pll_dco,
>> +	&a1_fixed_pll,
>> +	&a1_hifi_pll,
>> +	&a1_fclk_div2,
>> +	&a1_fclk_div3,
>> +	&a1_fclk_div5,
>> +	&a1_fclk_div7,
>> +};
>> +
>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>> +{
>> +	int ret;
>> +
>> +	ret = meson_eeclkc_probe(pdev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> +}
> 
> This function is useless.
> 
OK, I will use meson_eeclkc_probe derectly.
>> +
>> +static const struct meson_eeclkc_data a1_pll_data = {
>> +		.regmap_clks = a1_pll_regmaps,
>> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
>> +};
>> +static const struct of_device_id clkc_match_table[] = {
>> +	{
>> +		.compatible = "amlogic,a1-pll-clkc",
>> +		.data = &a1_pll_data
>> +	},
>> +	{ /* sentinel */ }
> 
> Nitpick: don't need to write this, just write the line like this
> 
OK, remove it.
> ' }, {}'
> 
>> +};
>> +
>> +static struct platform_driver a1_driver = {
>> +	.probe		= meson_a1_pll_probe,
>> +	.driver		= {
>> +		.name	= "a1-pll-clkc",
>> +		.of_match_table = clkc_match_table,
>> +	},
>> +};
>> +
>> +builtin_platform_driver(a1_driver);
>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>> new file mode 100644
>> index 0000000..99ee2a9
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1-pll.h
>> @@ -0,0 +1,56 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __A1_PLL_H
>> +#define __A1_PLL_H
>> +
>> +/* PLL register offset */
>> +#define ANACTRL_FIXPLL_CTRL0		0x80
>> +#define ANACTRL_FIXPLL_CTRL1		0x84
>> +#define ANACTRL_FIXPLL_CTRL2		0x88
>> +#define ANACTRL_FIXPLL_CTRL3		0x8c
>> +#define ANACTRL_FIXPLL_CTRL4		0x90
>> +#define ANACTRL_FIXPLL_STS		0x94
>> +#define ANACTRL_SYSPLL_CTRL0		0x100
>> +#define ANACTRL_SYSPLL_CTRL1		0x104
>> +#define ANACTRL_SYSPLL_CTRL2		0x108
>> +#define ANACTRL_SYSPLL_CTRL3		0x10c
>> +#define ANACTRL_SYSPLL_CTRL4		0x110
>> +#define ANACTRL_SYSPLL_STS		0x114
>> +#define ANACTRL_HIFIPLL_CTRL0		0x140
>> +#define ANACTRL_HIFIPLL_CTRL1		0x144
>> +#define ANACTRL_HIFIPLL_CTRL2		0x148
>> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
>> +#define ANACTRL_HIFIPLL_CTRL4		0x150
>> +#define ANACTRL_HIFIPLL_STS		0x154
>> +#define ANACTRL_AUDDDS_CTRL0		0x180
>> +#define ANACTRL_AUDDDS_CTRL1		0x184
>> +#define ANACTRL_AUDDDS_CTRL2		0x188
>> +#define ANACTRL_AUDDDS_CTRL3		0x18c
>> +#define ANACTRL_AUDDDS_CTRL4		0x190
>> +#define ANACTRL_AUDDDS_STS		0x194
>> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
>> +#define ANACTRL_POR_CNTL		0x208
>> +
>> +/*
>> + * CLKID index values
>> + *
>> + * These indices are entirely contrived and do not map onto the hardware.
>> + * It has now been decided to expose everything by default in the DT header:
>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
>> + * to expose, such as the internal muxes and dividers of composite clocks,
>> + * will remain defined here.
>> + */
>> +#define CLKID_FIXED_PLL_DCO		0
>> +#define CLKID_FCLK_DIV2_DIV		2
>> +#define CLKID_FCLK_DIV3_DIV		3
>> +#define CLKID_FCLK_DIV5_DIV		4
>> +#define CLKID_FCLK_DIV7_DIV		5
>> +#define NR_PLL_CLKS			11
>> +
>> +/* include the CLKIDs that have been made part of the DT binding */
>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>> +
>> +#endif /* __A1_PLL_H */
>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>> new file mode 100644
>> index 0000000..86a4733
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1.c
>> @@ -0,0 +1,2264 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + * Author: Jian Hu <jian.hu@amlogic.com>
>> + */
>> +
>> +#include <linux/platform_device.h>
>> +#include "clk-pll.h"
>> +#include "clk-dualdiv.h"
>> +#include "meson-eeclk.h"
>> +#include "a1.h"
> 
> Same as above
OK, I will change the order.
In fact, the clk-pll.h is not used in the current driver.
I will remove it.
> 
>> +
>> +/* PLLs clock in gates, its parent is xtal */
>> +static struct clk_regmap a1_xtal_clktree = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = SYS_OSCIN_CTRL,
>> +		.bit_idx = 0,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "xtal_clktree",
>> +		.ops = &clk_regmap_gate_ro_ops,
>> +		.parent_data = &(const struct clk_parent_data) {
>> +			.fw_name = "xtal",
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * switch for xtal clock
>> +		 * Linux should not change it at runtime
>> +		 */
> 
> Comment not useful: it uses the Ro ops
> 
OK,  remove the comments
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_xtal_fixpll = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = SYS_OSCIN_CTRL,
>> +		.bit_idx = 1,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "xtal_fixpll",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_data = &(const struct clk_parent_data) {
>> +			.fw_name = "xtal",
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_IS_CRITICAL,
>> +		/*
>> +		 * it feeds DDR,AXI,APB bus
>> +		 * Linux should not change it at runtime
>> +		 */
> 
> Again, the child are critical, not directly this clock from your
> comment.
> 
> Remove CRITICAL, put RO is linux is not supposed to touch it.
> 
repace as clk_regmap_gate_ro_ops
>> +	},
>> +};
>> +

[ ... ]

>> +
>> +/* dsp a clk */
>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>> +	{ .fw_name = "xtal", },
>> +	{ .fw_name = "fclk_div2", },
>> +	{ .fw_name = "fclk_div3", },
>> +	{ .fw_name = "fclk_div5", },
>> +	{ .fw_name = "hifi_pll", },
>> +	{ .hw = &a1_rtc_clk.hw },
>> +};
>> +
>> +static struct clk_regmap a1_dspa_a_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 10,
>> +		.table = mux_table_dsp_ab,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspa_a_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = dsp_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
> 
> .flags = CLK_SET_RATE_PARENT ?
Yes, I miss the flag.
> 
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_a_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.shift = 0,
>> +		.width = 10,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspa_a_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_a_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_a = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.bit_idx = 13,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspa_a",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_a_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_b_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 26,
>> +		.table = mux_table_dsp_ab,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspa_b_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = dsp_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
> 
> .flags = CLK_SET_RATE_PARENT ?
> 
Yes, I will add it.
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_b_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.shift = 16,
>> +		.width = 10,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspa_b_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_b_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_b = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.bit_idx = 29,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspa_b",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_b_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPA_CLK_CTRL0,
>> +		.mask = 0x1,
>> +		.shift = 15,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspa_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = (const struct clk_parent_data []) {
>> +			{ .hw = &a1_dspa_a.hw },
>> +			{ .hw = &a1_dspa_b.hw },
>> +		},
>> +		.num_parents = 2,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_en_dspa = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPA_CLK_EN,
>> +		.bit_idx = 1,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspa_en_dspa",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> 
> Why do you need CLK_IGNORE_UNUSED ?
> 
I should remove it
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspa_en_nic = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPA_CLK_EN,
>> +		.bit_idx = 0,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspa_en_nic",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspa_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> 
> Why do you need CLK_IGNORE_UNUSED ?
> 
I should remove it
>> +	},
>> +};
>> +
> 
> Same question and remarks applies to DSP B
> 
got it
>> +/* dsp b clk */
>> +static struct clk_regmap a1_dspb_a_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 10,
>> +		.table = mux_table_dsp_ab,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspb_a_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = dsp_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_a_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.shift = 0,
>> +		.width = 10,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspb_a_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_a_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_a = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.bit_idx = 13,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspb_a",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_a_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_b_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 26,
>> +		.table = mux_table_dsp_ab,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspb_b_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = dsp_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_b_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.shift = 16,
>> +		.width = 10,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspb_b_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_b_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_b = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.bit_idx = 29,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspb_b",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_b_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DSPB_CLK_CTRL0,
>> +		.mask = 0x1,
>> +		.shift = 15,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dspb_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
>> +		},
>> +		.num_parents = 2,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_en_dspb = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPB_CLK_EN,
>> +		.bit_idx = 1,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspb_en_dspb",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dspb_en_nic = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DSPB_CLK_EN,
>> +		.bit_idx = 0,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dspb_en_nic",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dspb_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +/* 12M/24M clock */
>> +static struct clk_regmap a1_24m = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = CLK12_24_CTRL,
>> +		.bit_idx = 11,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "24m",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_data = &(const struct clk_parent_data) {
>> +			.fw_name = "xtal",
>> +		},
>> +		.num_parents = 1,
>> +	},
>> +};
>> +

[ ... ]

>> +static struct clk_regmap a1_saradc_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = SAR_ADC_CLK_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 9,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "saradc_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = (const struct clk_parent_data []) {
>> +			{ .fw_name = "xtal", },
>> +			{ .hw = &a1_sys_clk.hw, },
>> +		},
>> +		.num_parents = 2,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_saradc_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = SAR_ADC_CLK_CTRL,
>> +		.shift = 0,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "saradc_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_saradc_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_saradc_clk = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = SAR_ADC_CLK_CTRL,
>> +		.bit_idx = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "saradc_clk",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_saradc_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +/* pwm a/b/c/d parent data */
>> +static const struct clk_parent_data pwm_parent_data[] = {
>> +	{ .fw_name = "xtal", },
>> +	{ .hw = &a1_sys_clk.hw },
>> +};
> 
> Looks like the same as SAR ADC
> 
OK, I will describe it like SAR ADC for pwm a/b/c/d
>> +
>> +/* pwm a clk */
>> +static struct clk_regmap a1_pwm_a_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 9,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_a_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_a_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.shift = 0,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_a_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_a_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_a = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.bit_idx = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_a",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_a_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * The CPU working voltage is controlled by pwm_a
>> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>> +		 * to avoid changing at runtime.
>                                      ^ it
> 
>> +		 * and is required by the platform to operate correctly.
>                     "blabla. And" is strange
> 
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> 
> This only skips the late_init() disable of unused clocks
> 
> Be aware that this is not fool-proof. If at any time a driver enable
> then disable the clock, the clock will be disable and I guess your
> platform will die if this provides the CPU voltage.
OK, CLK_IS_CRITICAL is better.
> 
>> +	},
>> +};
>> +
>> +/* pwm b clk */
>> +static struct clk_regmap a1_pwm_b_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 25,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_b_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_b_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.shift = 16,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_b_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_b_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_b = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_AB_CTRL,
>> +		.bit_idx = 24,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_b",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_b_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +/* pwm c clk */
>> +static struct clk_regmap a1_pwm_c_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 9,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_c_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_c_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.shift = 0,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_c_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_c_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_c = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.bit_idx = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_c",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_c_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +/* pwm d clk */
>> +static struct clk_regmap a1_pwm_d_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 25,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_d_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_d_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.shift = 16,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_d_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_d_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_d = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_CD_CTRL,
>> +		.bit_idx = 24,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_d",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_d_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>> +	{ .fw_name = "xtal", },
>> +	{ .hw = &a1_sys_clk.hw },
>> +	{ .fw_name = "fclk_div5", },
>> +	{ .hw = &a1_rtc_clk.hw },
>> +};
>> +
>> +/* pwm e clk */
>> +static struct clk_regmap a1_pwm_e_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.mask = 0x3,
>> +		.shift = 9,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_e_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_ef_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_e_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.shift = 0,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_e_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_e_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_e = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.bit_idx = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_e",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_e_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +/* pwm f clk */
>> +static struct clk_regmap a1_pwm_f_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.mask = 0x3,
>> +		.shift = 25,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_f_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = pwm_ef_parent_data,
>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_f_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.shift = 16,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "pwm_f_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_f_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_pwm_f = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = PWM_CLK_EF_CTRL,
>> +		.bit_idx = 24,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "pwm_f",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_pwm_f_div.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +

[ ... ]

>> +
>> +/* dmc clk */
>> +static struct clk_regmap a1_dmc_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DMC_CLK_CTRL,
>> +		.mask = 0x3,
>> +		.shift = 9,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dmc_sel",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = sd_emmc_parents,
>> +		.num_parents = 4,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dmc_div = {
>> +	.data = &(struct clk_regmap_div_data){
>> +		.offset = DMC_CLK_CTRL,
>> +		.shift = 0,
>> +		.width = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dmc_div",
>> +		.ops = &clk_regmap_divider_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dmc_sel.hw
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dmc_sel2 = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = DMC_CLK_CTRL,
>> +		.mask = 0x1,
>> +		.shift = 15,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "dmc_sel2",
>> +		.ops = &clk_regmap_mux_ops,
>> +		.parent_data = (const struct clk_parent_data []) {
>> +			{ .hw = &a1_dmc_div.hw },
>> +			{ .fw_name = "xtal", },
>> +		},
>> +		.num_parents = 2,
>> +		.flags = CLK_SET_RATE_PARENT,
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_dmc = {
>> +	.data = &(struct clk_regmap_gate_data){
>> +		.offset = DMC_CLK_CTRL,
>> +		.bit_idx = 8,
>> +	},
>> +	.hw.init = &(struct clk_init_data) {
>> +		.name = "dmc",
>> +		.ops = &clk_regmap_gate_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_dmc_sel2.hw
>> +		},
>> +		.num_parents = 1,
>> +		/*
>> +		 * This clock is used by DDR clock which setted in BL2
>> +		 * and is required by the platform to operate correctly.
>> +		 * Until the following condition are met, we need this clock to
>> +		 * be marked as critical:
>> +		 * a) Mark the clock used by a firmware resource, if possible
>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>> +		 *    clock stays on until the proper driver comes along
>> +		 */
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>> +	},
>> +};
> 
> Should you put all this DMC stuff in RO until you got a driver for it ?
OK, replace as clk_regmap_gate_ro_ops
> 
[ ... ]
>> +
>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>> +{
>> +	int ret;
>> +
>> +	ret = meson_eeclkc_probe(pdev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> +}
> 
> Again this function is function is useless and it makes me wonder if you
> should really be using meson_eeclkc_probe()
> 
> This makes you use syscon which is not correct unless you have a good
> reason ?
> 
If it can not use the meson_eeclkc_probe(), I will realize a probe 
function which is mostly duplicate with meson_eeclkc_probe() except 
"syscon_node_to_regmap"

Maybe another common probe function and a new file are required for A1 
three drivers? (include the CPU clock driver)

Or using meson_eeclkc_probe is more easier?

> Is there anything but clocks and resets in these register region ?
No, there is only clocks in the register region.
the same does the PLL register region.
> 
>> +
>> +static const struct meson_eeclkc_data a1_periphs_data = {
>> +		.regmap_clks = a1_periphs_regmaps,
>> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
>> +};
>> +static const struct of_device_id clkc_match_table[] = {
>> +	{
>> +		.compatible = "amlogic,a1-periphs-clkc",
>> +		.data = &a1_periphs_data
>> +	},
>> +	{ /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver a1_driver = {
>> +	.probe		= meson_a1_periphs_probe,
>> +	.driver		= {
>> +		.name	= "a1-periphs-clkc",
>> +		.of_match_table = clkc_match_table,
>> +	},
>> +};
>> +
>> +builtin_platform_driver(a1_driver);
>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>> new file mode 100644
>> index 0000000..1ae5e04
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1.h
>> @@ -0,0 +1,120 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#ifndef __A1_H
>> +#define __A1_H
>> +
>> +/* peripheral clock controller register offset */
>> +#define SYS_OSCIN_CTRL			0x0
>> +#define RTC_BY_OSCIN_CTRL0		0x4
>> +#define RTC_BY_OSCIN_CTRL1		0x8
>> +#define RTC_CTRL			0xc
>> +#define SYS_CLK_CTRL0			0x10
>> +#define AXI_CLK_CTRL0			0x14
>> +#define SYS_CLK_EN0			0x1c
>> +#define SYS_CLK_EN1			0x20
>> +#define AXI_CLK_EN			0x24
>> +#define DSPA_CLK_EN			0x28
>> +#define DSPB_CLK_EN			0x2c
>> +#define DSPA_CLK_CTRL0			0x30
>> +#define DSPB_CLK_CTRL0			0x34
>> +#define CLK12_24_CTRL			0x38
>> +#define GEN_CLK_CTRL			0x3c
>> +#define TIMESTAMP_CTRL0			0x40
>> +#define TIMESTAMP_CTRL1			0x44
>> +#define TIMESTAMP_CTRL2			0x48
>> +#define TIMESTAMP_VAL0			0x4c
>> +#define TIMESTAMP_VAL1			0x50
>> +#define TIMEBASE_CTRL0			0x54
>> +#define TIMEBASE_CTRL1			0x58
>> +#define SAR_ADC_CLK_CTRL		0xc0
>> +#define PWM_CLK_AB_CTRL			0xc4
>> +#define PWM_CLK_CD_CTRL			0xc8
>> +#define PWM_CLK_EF_CTRL			0xcc
>> +#define SPICC_CLK_CTRL			0xd0
>> +#define TS_CLK_CTRL			0xd4
>> +#define SPIFC_CLK_CTRL			0xd8
>> +#define USB_BUSCLK_CTRL			0xdc
>> +#define SD_EMMC_CLK_CTRL		0xe0
>> +#define CECA_CLK_CTRL0			0xe4
>> +#define CECA_CLK_CTRL1			0xe8
>> +#define CECB_CLK_CTRL0			0xec
>> +#define CECB_CLK_CTRL1			0xf0
>> +#define PSRAM_CLK_CTRL			0xf4
>> +#define DMC_CLK_CTRL			0xf8
>> +#define FCLK_DIV1_SEL			0xfc
>> +#define TST_CTRL			0x100
>> +
>> +#define CLKID_XTAL_CLKTREE		0
>> +#define CLKID_SYS_A_SEL			89
>> +#define CLKID_SYS_A_DIV			90
>> +#define CLKID_SYS_A			91
>> +#define CLKID_SYS_B_SEL			92
>> +#define CLKID_SYS_B_DIV			93
>> +#define CLKID_SYS_B			94
>> +#define CLKID_DSPA_A_SEL		95
>> +#define CLKID_DSPA_A_DIV		96
>> +#define CLKID_DSPA_A			97
>> +#define CLKID_DSPA_B_SEL		98
>> +#define CLKID_DSPA_B_DIV		99
>> +#define CLKID_DSPA_B			100
>> +#define CLKID_DSPB_A_SEL		101
>> +#define CLKID_DSPB_A_DIV		102
>> +#define CLKID_DSPB_A			103
>> +#define CLKID_DSPB_B_SEL		104
>> +#define CLKID_DSPB_B_DIV		105
>> +#define CLKID_DSPB_B			106
>> +#define CLKID_RTC_32K_CLKIN		107
>> +#define CLKID_RTC_32K_DIV		108
>> +#define CLKID_RTC_32K_XTAL		109
>> +#define CLKID_RTC_32K_SEL		110
>> +#define CLKID_CECB_32K_CLKIN		111
>> +#define CLKID_CECB_32K_DIV		112
>> +#define CLKID_CECB_32K_SEL_PRE		113
>> +#define CLKID_CECB_32K_SEL		114
>> +#define CLKID_CECA_32K_CLKIN		115
>> +#define CLKID_CECA_32K_DIV		116
>> +#define CLKID_CECA_32K_SEL_PRE		117
>> +#define CLKID_CECA_32K_SEL		118
>> +#define CLKID_DIV2_PRE			119
>> +#define CLKID_24M_DIV2			120
>> +#define CLKID_GEN_SEL			121
>> +#define CLKID_GEN_DIV			122
>> +#define CLKID_SARADC_DIV		123
>> +#define CLKID_PWM_A_SEL			124
>> +#define CLKID_PWM_A_DIV			125
>> +#define CLKID_PWM_B_SEL			126
>> +#define CLKID_PWM_B_DIV			127
>> +#define CLKID_PWM_C_SEL			128
>> +#define CLKID_PWM_C_DIV			129
>> +#define CLKID_PWM_D_SEL			130
>> +#define CLKID_PWM_D_DIV			131
>> +#define CLKID_PWM_E_SEL			132
>> +#define CLKID_PWM_E_DIV			133
>> +#define CLKID_PWM_F_SEL			134
>> +#define CLKID_PWM_F_DIV			135
>> +#define CLKID_SPICC_SEL			136
>> +#define CLKID_SPICC_DIV			137
>> +#define CLKID_SPICC_SEL2		138
>> +#define CLKID_TS_DIV			139
>> +#define CLKID_SPIFC_SEL			140
>> +#define CLKID_SPIFC_DIV			141
>> +#define CLKID_SPIFC_SEL2		142
>> +#define CLKID_USB_BUS_SEL		143
>> +#define CLKID_USB_BUS_DIV		144
>> +#define CLKID_SD_EMMC_SEL		145
>> +#define CLKID_SD_EMMC_DIV		146
>> +#define CLKID_SD_EMMC_SEL2		147
>> +#define CLKID_PSRAM_SEL			148
>> +#define CLKID_PSRAM_DIV			149
>> +#define CLKID_PSRAM_SEL2		150
>> +#define CLKID_DMC_SEL			151
>> +#define CLKID_DMC_DIV			152
>> +#define CLKID_DMC_SEL2			153
>> +#define NR_CLKS				154
>> +
>> +#include <dt-bindings/clock/a1-clkc.h>
>> +
>> +#endif /* __A1_H */
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-25 11:32     ` Jian Hu
@ 2019-11-04  8:24       ` Jerome Brunet
  2019-11-09 11:16         ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-11-04  8:24 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Jerome
>
> Thanks for your review
>
> On 2019/10/21 19:41, Jerome Brunet wrote:
>>
>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> The Amlogic A1 clock includes three drivers:
>>> peripheral clocks, pll clocks, CPU clocks.
>>> sys pll and CPU clocks will be sent in next patch.
>>>
>>> Unlike the previous series, there is no EE/AO domain
>>> in A1 CLK controllers.
>>>
>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>> ---
>>>   drivers/clk/meson/Kconfig  |   10 +
>>>   drivers/clk/meson/Makefile |    1 +
>>>   drivers/clk/meson/a1-pll.c |  345 +++++++
>>>   drivers/clk/meson/a1-pll.h |   56 ++
>>>   drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>>>   drivers/clk/meson/a1.h     |  120 +++
>>>   6 files changed, 2796 insertions(+)
>>>   create mode 100644 drivers/clk/meson/a1-pll.c
>>>   create mode 100644 drivers/clk/meson/a1-pll.h
>>>   create mode 100644 drivers/clk/meson/a1.c
>>>   create mode 100644 drivers/clk/meson/a1.h
>>
>> In the next version, one
> OK, I will send a1 peripheral and pll driver in two patch.
>>
>>>
>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>> index dabeb43..c2809b2 100644
>>> --- a/drivers/clk/meson/Kconfig
>>> +++ b/drivers/clk/meson/Kconfig
>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>   	  Support for the audio clock controller on AmLogic A113D devices,
>>>   	  aka axg, Say Y if you want audio subsystem to work.
>>>   +config COMMON_CLK_A1
>>> +	bool
>>> +	depends on ARCH_MESON
>>> +	select COMMON_CLK_MESON_REGMAP
>>> +	select COMMON_CLK_MESON_DUALDIV
>>> +	select COMMON_CLK_MESON_PLL
>>> +	help
>>> +	  Support for the clock controller on Amlogic A113L device,
>>> +	  aka a1. Say Y if you want peripherals to work.
>>> +
>>>   config COMMON_CLK_G12A
>>>   	bool
>>>   	depends on ARCH_MESON
>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>> index 3939f21..28cbae1 100644
>>> --- a/drivers/clk/meson/Makefile
>>> +++ b/drivers/clk/meson/Makefile
>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>>>     obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>   obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>
>> So far, all the controller had there own option, I don't see why it
>> should be different here.
>>
> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll driver
>>>   obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>   obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>   obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>> new file mode 100644
>>> index 0000000..486d964
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1-pll.c
>>> @@ -0,0 +1,345 @@
>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>> + */
>>> +
>>> +#include <linux/platform_device.h>
>>
>> Hum ... looks like some things are missing here
>>
>> #include <linux/of_device.h>
>> #include <linux/clk-provider.h>
>>
>> ?
> #1
> There is <linux/clk-provider.h> in meson-eeclk.h file,
>
> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>
> #2
> For A1 driver, the file "linux/of_device.h" is not required.
> It is required by meson-eeclk.c in fact.

You are using what is provided by these headers directly in this file
If meson-eeclk ever changes, your driver breaks

>>
>>> +#include "clk-pll.h"
>>> +#include "meson-eeclk.h"
>>> +#include "a1-pll.h"
>>
>> Alphanumeric order please
>>
> OK, I will change it in the next version.
>
>>> +
>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>> +	.data = &(struct meson_clk_pll_data){
>>> +		.en = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>> +			.shift   = 28,
>>> +			.width   = 1,
>>> +		},
>>> +		.m = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>> +			.shift   = 0,
>>> +			.width   = 8,
>>> +		},
>>> +		.n = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>> +			.shift   = 10,
>>> +			.width   = 5,
>>> +		},
>>> +		.frac = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
>>> +			.shift   = 0,
>>> +			.width   = 19,
>>> +		},
>>> +		.l = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>> +			.shift   = 31,
>>> +			.width   = 1,
>>> +		},
>>> +		.rst = {
>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>> +			.shift   = 29,
>>> +			.width   = 1,
>>> +		},
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fixed_pll_dco",
>>> +		.ops = &meson_clk_pll_ro_ops,
>>> +		.parent_data = &(const struct clk_parent_data){
>>> +			.fw_name = "xtal_fixpll",
>>> +			.name = "xtal_fixpll",
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_fixed_pll = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>> +		.bit_idx = 20,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "fixed_pll",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fixed_pll_dco.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * This clock is fclk_div2/3/4's parent,
>>> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>
>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>
>>> +		 * It is required by the platform to operate correctly.
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>
>> Don't blindly copy/paste comments from other drivers. There is no driver
>> for the devices you are mentionning so the end of the comment is
>> confusing. The 3 first lines were enough
>>
> OK, I will remove the confusing comments
>
>>> +		.flags = CLK_IS_CRITICAL,
>>
>>>From your comment, I understand that some child are critical, not this
>> particular (or at least, not directly). So this can be removed AFAICT
>>
>> You should even need CLK_IGNORE_UNUSED for this one since the clock will
>> already be enabled before the late_init() kicks in
>>
> OK, I will replace it as CLK_IGNORE_UNUSED.
>>> +	},
>>> +};
>>> +
>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>> +	.min = 32,
>>> +	.max = 64,
>>> +};
>>> +
>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>> +};
>>> +
>>> +static struct clk_regmap a1_hifi_pll = {
>>> +	.data = &(struct meson_clk_pll_data){
>>> +		.en = {
>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> +			.shift   = 28,
>>> +			.width   = 1,
>>> +		},
>>> +		.m = {
>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> +			.shift   = 0,
>>> +			.width   = 8,
>>> +		},
>>> +		.n = {
>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> +			.shift   = 10,
>>> +			.width   = 5,
>>> +		},
>>> +		.frac = {
>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
>>> +			.shift   = 0,
>>> +			.width   = 19,
>>> +		},
>>> +		.l = {
>>> +			.reg_off = ANACTRL_HIFIPLL_STS,
>>> +			.shift   = 31,
>>> +			.width   = 1,
>>> +		},
>>> +		.range = &a1_hifi_pll_mult_range,
>>> +		.init_regs = a1_hifi_init_regs,
>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>> +		.strict_sequence = true,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "hifi_pll",
>>> +		.ops = &meson_clk_pll_ops,
>>> +		.parent_data = &(const struct clk_parent_data){
>>> +			.fw_name = "xtal_fixpll",
>>> +			.name = "xtal_fixpll",
>>
>> Both should provided when a controller transition from the old way of
>> describing parent to the new way. This is a new controller so it does
>> not apply.
> I do not understand why it does not apply, could you explain more?

Your driver is new, it is not something old transitioning from global
name to clock in DT !

>
> The xtal_fixpll clock is registered in another peripheral driver, If do not
> desribe the "name" member in parent_data, "fw_name" does not work because
> it has not been registered. the hifi_pll parent will be null in
> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>
> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.

There will be an orphan yes, temporarily, until both controllers are up.
Once both controller are up, the clock will be reparented if necessary.

>
> So both of "fw_name" of "name" should be described.

No

>
>>
>> Same for the other occurences.
>>
>> Also, I think you meant xtal_hifipll
> Yes,I will correct it.
>>
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>> +	.mult = 1,
>>> +	.div = 2,
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div2_div",
>>> +		.ops = &clk_fixed_factor_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fixed_pll.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_fclk_div2 = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>> +		.bit_idx = 21,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div2",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fclk_div2_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * This clock is used by DDR clock in BL2 firmware
>>> +		 * and is required by the platform to operate correctly.
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>> +	.mult = 1,
>>> +	.div = 3,
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div3_div",
>>> +		.ops = &clk_fixed_factor_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fixed_pll.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_fclk_div3 = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>> +		.bit_idx = 22,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div3",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fclk_div3_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * This clock is used by APB bus which setted in Romcode
>>> +		 * and is required by the platform to operate correctly.
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>> +	.mult = 1,
>>> +	.div = 5,
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div5_div",
>>> +		.ops = &clk_fixed_factor_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fixed_pll.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_fclk_div5 = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>> +		.bit_idx = 23,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div5",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fclk_div5_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * This clock is used by AXI bus which setted in Romcode
>>> +		 * and is required by the platform to operate correctly.
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>> +	.mult = 1,
>>> +	.div = 7,
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div7_div",
>>> +		.ops = &clk_fixed_factor_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fixed_pll.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_fclk_div7 = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>> +		.bit_idx = 24,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "fclk_div7",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_fclk_div7_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>>> +/* Array of all clocks provided by this provider */
>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>> +	.hws = {
>>> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
>>> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
>>> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
>>> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
>>> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
>>> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
>>> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
>>> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
>>> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
>>> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
>>> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
>>> +		[NR_PLL_CLKS]			= NULL,
>>> +	},
>>> +	.num = NR_PLL_CLKS,
>>> +};
>>> +
>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>> +	&a1_fixed_pll_dco,
>>> +	&a1_fixed_pll,
>>> +	&a1_hifi_pll,
>>> +	&a1_fclk_div2,
>>> +	&a1_fclk_div3,
>>> +	&a1_fclk_div5,
>>> +	&a1_fclk_div7,
>>> +};
>>> +
>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>> +{
>>> +	int ret;
>>> +
>>> +	ret = meson_eeclkc_probe(pdev);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return 0;
>>> +}
>>
>> This function is useless.
>>
> OK, I will use meson_eeclkc_probe derectly.
>>> +
>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>> +		.regmap_clks = a1_pll_regmaps,
>>> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
>>> +};
>>> +static const struct of_device_id clkc_match_table[] = {
>>> +	{
>>> +		.compatible = "amlogic,a1-pll-clkc",
>>> +		.data = &a1_pll_data
>>> +	},
>>> +	{ /* sentinel */ }
>>
>> Nitpick: don't need to write this, just write the line like this
>>
> OK, remove it.
>> ' }, {}'
>>
>>> +};
>>> +
>>> +static struct platform_driver a1_driver = {
>>> +	.probe		= meson_a1_pll_probe,
>>> +	.driver		= {
>>> +		.name	= "a1-pll-clkc",
>>> +		.of_match_table = clkc_match_table,
>>> +	},
>>> +};
>>> +
>>> +builtin_platform_driver(a1_driver);
>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>> new file mode 100644
>>> index 0000000..99ee2a9
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1-pll.h
>>> @@ -0,0 +1,56 @@
>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + */
>>> +
>>> +#ifndef __A1_PLL_H
>>> +#define __A1_PLL_H
>>> +
>>> +/* PLL register offset */
>>> +#define ANACTRL_FIXPLL_CTRL0		0x80
>>> +#define ANACTRL_FIXPLL_CTRL1		0x84
>>> +#define ANACTRL_FIXPLL_CTRL2		0x88
>>> +#define ANACTRL_FIXPLL_CTRL3		0x8c
>>> +#define ANACTRL_FIXPLL_CTRL4		0x90
>>> +#define ANACTRL_FIXPLL_STS		0x94
>>> +#define ANACTRL_SYSPLL_CTRL0		0x100
>>> +#define ANACTRL_SYSPLL_CTRL1		0x104
>>> +#define ANACTRL_SYSPLL_CTRL2		0x108
>>> +#define ANACTRL_SYSPLL_CTRL3		0x10c
>>> +#define ANACTRL_SYSPLL_CTRL4		0x110
>>> +#define ANACTRL_SYSPLL_STS		0x114
>>> +#define ANACTRL_HIFIPLL_CTRL0		0x140
>>> +#define ANACTRL_HIFIPLL_CTRL1		0x144
>>> +#define ANACTRL_HIFIPLL_CTRL2		0x148
>>> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
>>> +#define ANACTRL_HIFIPLL_CTRL4		0x150
>>> +#define ANACTRL_HIFIPLL_STS		0x154
>>> +#define ANACTRL_AUDDDS_CTRL0		0x180
>>> +#define ANACTRL_AUDDDS_CTRL1		0x184
>>> +#define ANACTRL_AUDDDS_CTRL2		0x188
>>> +#define ANACTRL_AUDDDS_CTRL3		0x18c
>>> +#define ANACTRL_AUDDDS_CTRL4		0x190
>>> +#define ANACTRL_AUDDDS_STS		0x194
>>> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
>>> +#define ANACTRL_POR_CNTL		0x208
>>> +
>>> +/*
>>> + * CLKID index values
>>> + *
>>> + * These indices are entirely contrived and do not map onto the hardware.
>>> + * It has now been decided to expose everything by default in the DT header:
>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
>>> + * to expose, such as the internal muxes and dividers of composite clocks,
>>> + * will remain defined here.
>>> + */
>>> +#define CLKID_FIXED_PLL_DCO		0
>>> +#define CLKID_FCLK_DIV2_DIV		2
>>> +#define CLKID_FCLK_DIV3_DIV		3
>>> +#define CLKID_FCLK_DIV5_DIV		4
>>> +#define CLKID_FCLK_DIV7_DIV		5
>>> +#define NR_PLL_CLKS			11
>>> +
>>> +/* include the CLKIDs that have been made part of the DT binding */
>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>> +
>>> +#endif /* __A1_PLL_H */
>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>> new file mode 100644
>>> index 0000000..86a4733
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1.c
>>> @@ -0,0 +1,2264 @@
>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>> + */
>>> +
>>> +#include <linux/platform_device.h>
>>> +#include "clk-pll.h"
>>> +#include "clk-dualdiv.h"
>>> +#include "meson-eeclk.h"
>>> +#include "a1.h"
>>
>> Same as above
> OK, I will change the order.
> In fact, the clk-pll.h is not used in the current driver.
> I will remove it.
>>
>>> +
>>> +/* PLLs clock in gates, its parent is xtal */
>>> +static struct clk_regmap a1_xtal_clktree = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = SYS_OSCIN_CTRL,
>>> +		.bit_idx = 0,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "xtal_clktree",
>>> +		.ops = &clk_regmap_gate_ro_ops,
>>> +		.parent_data = &(const struct clk_parent_data) {
>>> +			.fw_name = "xtal",
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * switch for xtal clock
>>> +		 * Linux should not change it at runtime
>>> +		 */
>>
>> Comment not useful: it uses the Ro ops
>>
> OK,  remove the comments
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_xtal_fixpll = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = SYS_OSCIN_CTRL,
>>> +		.bit_idx = 1,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "xtal_fixpll",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_data = &(const struct clk_parent_data) {
>>> +			.fw_name = "xtal",
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_IS_CRITICAL,
>>> +		/*
>>> +		 * it feeds DDR,AXI,APB bus
>>> +		 * Linux should not change it at runtime
>>> +		 */
>>
>> Again, the child are critical, not directly this clock from your
>> comment.
>>
>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>
> repace as clk_regmap_gate_ro_ops
>>> +	},
>>> +};
>>> +
>
> [ ... ]
>
>>> +
>>> +/* dsp a clk */
>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>> +	{ .fw_name = "xtal", },
>>> +	{ .fw_name = "fclk_div2", },
>>> +	{ .fw_name = "fclk_div3", },
>>> +	{ .fw_name = "fclk_div5", },
>>> +	{ .fw_name = "hifi_pll", },
>>> +	{ .hw = &a1_rtc_clk.hw },
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_a_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 10,
>>> +		.table = mux_table_dsp_ab,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspa_a_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = dsp_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>
>> .flags = CLK_SET_RATE_PARENT ?
> Yes, I miss the flag.
>>
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_a_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.shift = 0,
>>> +		.width = 10,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspa_a_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_a_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_a = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.bit_idx = 13,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspa_a",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_a_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_b_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 26,
>>> +		.table = mux_table_dsp_ab,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspa_b_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = dsp_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>
>> .flags = CLK_SET_RATE_PARENT ?
>>
> Yes, I will add it.
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_b_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.shift = 16,
>>> +		.width = 10,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspa_b_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_b_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_b = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.bit_idx = 29,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspa_b",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_b_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPA_CLK_CTRL0,
>>> +		.mask = 0x1,
>>> +		.shift = 15,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspa_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = (const struct clk_parent_data []) {
>>> +			{ .hw = &a1_dspa_a.hw },
>>> +			{ .hw = &a1_dspa_b.hw },
>>> +		},
>>> +		.num_parents = 2,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPA_CLK_EN,
>>> +		.bit_idx = 1,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspa_en_dspa",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>
>> Why do you need CLK_IGNORE_UNUSED ?
>>
> I should remove it
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspa_en_nic = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPA_CLK_EN,
>>> +		.bit_idx = 0,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspa_en_nic",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspa_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>
>> Why do you need CLK_IGNORE_UNUSED ?
>>
> I should remove it
>>> +	},
>>> +};
>>> +
>>
>> Same question and remarks applies to DSP B
>>
> got it
>>> +/* dsp b clk */
>>> +static struct clk_regmap a1_dspb_a_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 10,
>>> +		.table = mux_table_dsp_ab,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspb_a_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = dsp_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_a_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.shift = 0,
>>> +		.width = 10,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspb_a_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_a_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_a = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.bit_idx = 13,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspb_a",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_a_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_b_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 26,
>>> +		.table = mux_table_dsp_ab,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspb_b_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = dsp_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_b_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.shift = 16,
>>> +		.width = 10,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspb_b_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_b_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_b = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.bit_idx = 29,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspb_b",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_b_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DSPB_CLK_CTRL0,
>>> +		.mask = 0x1,
>>> +		.shift = 15,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dspb_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
>>> +		},
>>> +		.num_parents = 2,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPB_CLK_EN,
>>> +		.bit_idx = 1,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspb_en_dspb",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dspb_en_nic = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DSPB_CLK_EN,
>>> +		.bit_idx = 0,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dspb_en_nic",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dspb_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +/* 12M/24M clock */
>>> +static struct clk_regmap a1_24m = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = CLK12_24_CTRL,
>>> +		.bit_idx = 11,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "24m",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_data = &(const struct clk_parent_data) {
>>> +			.fw_name = "xtal",
>>> +		},
>>> +		.num_parents = 1,
>>> +	},
>>> +};
>>> +
>
> [ ... ]
>
>>> +static struct clk_regmap a1_saradc_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = SAR_ADC_CLK_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 9,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "saradc_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = (const struct clk_parent_data []) {
>>> +			{ .fw_name = "xtal", },
>>> +			{ .hw = &a1_sys_clk.hw, },
>>> +		},
>>> +		.num_parents = 2,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_saradc_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = SAR_ADC_CLK_CTRL,
>>> +		.shift = 0,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "saradc_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_saradc_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_saradc_clk = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = SAR_ADC_CLK_CTRL,
>>> +		.bit_idx = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "saradc_clk",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_saradc_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +/* pwm a/b/c/d parent data */
>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>> +	{ .fw_name = "xtal", },
>>> +	{ .hw = &a1_sys_clk.hw },
>>> +};
>>
>> Looks like the same as SAR ADC
>>
> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>> +
>>> +/* pwm a clk */
>>> +static struct clk_regmap a1_pwm_a_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 9,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_a_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_a_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.shift = 0,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_a_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_a_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_a = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.bit_idx = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_a",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_a_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * The CPU working voltage is controlled by pwm_a
>>> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>> +		 * to avoid changing at runtime.
>>                                      ^ it
>>
>>> +		 * and is required by the platform to operate correctly.
>>                     "blabla. And" is strange
>>
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>
>> This only skips the late_init() disable of unused clocks
>>
>> Be aware that this is not fool-proof. If at any time a driver enable
>> then disable the clock, the clock will be disable and I guess your
>> platform will die if this provides the CPU voltage.
> OK, CLK_IS_CRITICAL is better.
>>
>>> +	},
>>> +};
>>> +
>>> +/* pwm b clk */
>>> +static struct clk_regmap a1_pwm_b_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 25,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_b_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_b_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.shift = 16,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_b_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_b_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_b = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_AB_CTRL,
>>> +		.bit_idx = 24,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_b",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_b_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +/* pwm c clk */
>>> +static struct clk_regmap a1_pwm_c_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 9,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_c_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_c_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.shift = 0,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_c_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_c_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_c = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.bit_idx = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_c",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_c_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +/* pwm d clk */
>>> +static struct clk_regmap a1_pwm_d_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 25,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_d_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_d_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.shift = 16,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_d_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_d_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_d = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_CD_CTRL,
>>> +		.bit_idx = 24,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_d",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_d_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>> +	{ .fw_name = "xtal", },
>>> +	{ .hw = &a1_sys_clk.hw },
>>> +	{ .fw_name = "fclk_div5", },
>>> +	{ .hw = &a1_rtc_clk.hw },
>>> +};
>>> +
>>> +/* pwm e clk */
>>> +static struct clk_regmap a1_pwm_e_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.mask = 0x3,
>>> +		.shift = 9,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_e_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_ef_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_e_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.shift = 0,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_e_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_e_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_e = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.bit_idx = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_e",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_e_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +/* pwm f clk */
>>> +static struct clk_regmap a1_pwm_f_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.mask = 0x3,
>>> +		.shift = 25,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_f_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = pwm_ef_parent_data,
>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_f_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.shift = 16,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "pwm_f_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_f_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_pwm_f = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = PWM_CLK_EF_CTRL,
>>> +		.bit_idx = 24,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "pwm_f",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_pwm_f_div.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>
> [ ... ]
>
>>> +
>>> +/* dmc clk */
>>> +static struct clk_regmap a1_dmc_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DMC_CLK_CTRL,
>>> +		.mask = 0x3,
>>> +		.shift = 9,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dmc_sel",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = sd_emmc_parents,
>>> +		.num_parents = 4,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dmc_div = {
>>> +	.data = &(struct clk_regmap_div_data){
>>> +		.offset = DMC_CLK_CTRL,
>>> +		.shift = 0,
>>> +		.width = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dmc_div",
>>> +		.ops = &clk_regmap_divider_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dmc_sel.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dmc_sel2 = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = DMC_CLK_CTRL,
>>> +		.mask = 0x1,
>>> +		.shift = 15,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "dmc_sel2",
>>> +		.ops = &clk_regmap_mux_ops,
>>> +		.parent_data = (const struct clk_parent_data []) {
>>> +			{ .hw = &a1_dmc_div.hw },
>>> +			{ .fw_name = "xtal", },
>>> +		},
>>> +		.num_parents = 2,
>>> +		.flags = CLK_SET_RATE_PARENT,
>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_dmc = {
>>> +	.data = &(struct clk_regmap_gate_data){
>>> +		.offset = DMC_CLK_CTRL,
>>> +		.bit_idx = 8,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data) {
>>> +		.name = "dmc",
>>> +		.ops = &clk_regmap_gate_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_dmc_sel2.hw
>>> +		},
>>> +		.num_parents = 1,
>>> +		/*
>>> +		 * This clock is used by DDR clock which setted in BL2
>>> +		 * and is required by the platform to operate correctly.
>>> +		 * Until the following condition are met, we need this clock to
>>> +		 * be marked as critical:
>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>> +		 *    clock stays on until the proper driver comes along
>>> +		 */
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>
>> Should you put all this DMC stuff in RO until you got a driver for it ?
> OK, replace as clk_regmap_gate_ro_ops
>>
> [ ... ]
>>> +
>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>> +{
>>> +	int ret;
>>> +
>>> +	ret = meson_eeclkc_probe(pdev);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return 0;
>>> +}
>>
>> Again this function is function is useless and it makes me wonder if you
>> should really be using meson_eeclkc_probe()
>>
>> This makes you use syscon which is not correct unless you have a good
>> reason ?
>>
> If it can not use the meson_eeclkc_probe(), I will realize a probe function
> which is mostly duplicate with meson_eeclkc_probe() except
> "syscon_node_to_regmap"
>
> Maybe another common probe function and a new file are required for A1
> three drivers? (include the CPU clock driver)

Maybe

>
> Or using meson_eeclkc_probe is more easier?

It is not question of easiness, but correctness.

>
>> Is there anything but clocks and resets in these register region ?
> No, there is only clocks in the register region.
> the same does the PLL register region.

Then there is no reason to use syscon for those drivers

>>
>>> +
>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>> +		.regmap_clks = a1_periphs_regmaps,
>>> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
>>> +};
>>> +static const struct of_device_id clkc_match_table[] = {
>>> +	{
>>> +		.compatible = "amlogic,a1-periphs-clkc",
>>> +		.data = &a1_periphs_data
>>> +	},
>>> +	{ /* sentinel */ }
>>> +};
>>> +
>>> +static struct platform_driver a1_driver = {
>>> +	.probe		= meson_a1_periphs_probe,
>>> +	.driver		= {
>>> +		.name	= "a1-periphs-clkc",
>>> +		.of_match_table = clkc_match_table,
>>> +	},
>>> +};
>>> +
>>> +builtin_platform_driver(a1_driver);
>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>> new file mode 100644
>>> index 0000000..1ae5e04
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1.h
>>> @@ -0,0 +1,120 @@
>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + */
>>> +
>>> +#ifndef __A1_H
>>> +#define __A1_H
>>> +
>>> +/* peripheral clock controller register offset */
>>> +#define SYS_OSCIN_CTRL			0x0
>>> +#define RTC_BY_OSCIN_CTRL0		0x4
>>> +#define RTC_BY_OSCIN_CTRL1		0x8
>>> +#define RTC_CTRL			0xc
>>> +#define SYS_CLK_CTRL0			0x10
>>> +#define AXI_CLK_CTRL0			0x14
>>> +#define SYS_CLK_EN0			0x1c
>>> +#define SYS_CLK_EN1			0x20
>>> +#define AXI_CLK_EN			0x24
>>> +#define DSPA_CLK_EN			0x28
>>> +#define DSPB_CLK_EN			0x2c
>>> +#define DSPA_CLK_CTRL0			0x30
>>> +#define DSPB_CLK_CTRL0			0x34
>>> +#define CLK12_24_CTRL			0x38
>>> +#define GEN_CLK_CTRL			0x3c
>>> +#define TIMESTAMP_CTRL0			0x40
>>> +#define TIMESTAMP_CTRL1			0x44
>>> +#define TIMESTAMP_CTRL2			0x48
>>> +#define TIMESTAMP_VAL0			0x4c
>>> +#define TIMESTAMP_VAL1			0x50
>>> +#define TIMEBASE_CTRL0			0x54
>>> +#define TIMEBASE_CTRL1			0x58
>>> +#define SAR_ADC_CLK_CTRL		0xc0
>>> +#define PWM_CLK_AB_CTRL			0xc4
>>> +#define PWM_CLK_CD_CTRL			0xc8
>>> +#define PWM_CLK_EF_CTRL			0xcc
>>> +#define SPICC_CLK_CTRL			0xd0
>>> +#define TS_CLK_CTRL			0xd4
>>> +#define SPIFC_CLK_CTRL			0xd8
>>> +#define USB_BUSCLK_CTRL			0xdc
>>> +#define SD_EMMC_CLK_CTRL		0xe0
>>> +#define CECA_CLK_CTRL0			0xe4
>>> +#define CECA_CLK_CTRL1			0xe8
>>> +#define CECB_CLK_CTRL0			0xec
>>> +#define CECB_CLK_CTRL1			0xf0
>>> +#define PSRAM_CLK_CTRL			0xf4
>>> +#define DMC_CLK_CTRL			0xf8
>>> +#define FCLK_DIV1_SEL			0xfc
>>> +#define TST_CTRL			0x100
>>> +
>>> +#define CLKID_XTAL_CLKTREE		0
>>> +#define CLKID_SYS_A_SEL			89
>>> +#define CLKID_SYS_A_DIV			90
>>> +#define CLKID_SYS_A			91
>>> +#define CLKID_SYS_B_SEL			92
>>> +#define CLKID_SYS_B_DIV			93
>>> +#define CLKID_SYS_B			94
>>> +#define CLKID_DSPA_A_SEL		95
>>> +#define CLKID_DSPA_A_DIV		96
>>> +#define CLKID_DSPA_A			97
>>> +#define CLKID_DSPA_B_SEL		98
>>> +#define CLKID_DSPA_B_DIV		99
>>> +#define CLKID_DSPA_B			100
>>> +#define CLKID_DSPB_A_SEL		101
>>> +#define CLKID_DSPB_A_DIV		102
>>> +#define CLKID_DSPB_A			103
>>> +#define CLKID_DSPB_B_SEL		104
>>> +#define CLKID_DSPB_B_DIV		105
>>> +#define CLKID_DSPB_B			106
>>> +#define CLKID_RTC_32K_CLKIN		107
>>> +#define CLKID_RTC_32K_DIV		108
>>> +#define CLKID_RTC_32K_XTAL		109
>>> +#define CLKID_RTC_32K_SEL		110
>>> +#define CLKID_CECB_32K_CLKIN		111
>>> +#define CLKID_CECB_32K_DIV		112
>>> +#define CLKID_CECB_32K_SEL_PRE		113
>>> +#define CLKID_CECB_32K_SEL		114
>>> +#define CLKID_CECA_32K_CLKIN		115
>>> +#define CLKID_CECA_32K_DIV		116
>>> +#define CLKID_CECA_32K_SEL_PRE		117
>>> +#define CLKID_CECA_32K_SEL		118
>>> +#define CLKID_DIV2_PRE			119
>>> +#define CLKID_24M_DIV2			120
>>> +#define CLKID_GEN_SEL			121
>>> +#define CLKID_GEN_DIV			122
>>> +#define CLKID_SARADC_DIV		123
>>> +#define CLKID_PWM_A_SEL			124
>>> +#define CLKID_PWM_A_DIV			125
>>> +#define CLKID_PWM_B_SEL			126
>>> +#define CLKID_PWM_B_DIV			127
>>> +#define CLKID_PWM_C_SEL			128
>>> +#define CLKID_PWM_C_DIV			129
>>> +#define CLKID_PWM_D_SEL			130
>>> +#define CLKID_PWM_D_DIV			131
>>> +#define CLKID_PWM_E_SEL			132
>>> +#define CLKID_PWM_E_DIV			133
>>> +#define CLKID_PWM_F_SEL			134
>>> +#define CLKID_PWM_F_DIV			135
>>> +#define CLKID_SPICC_SEL			136
>>> +#define CLKID_SPICC_DIV			137
>>> +#define CLKID_SPICC_SEL2		138
>>> +#define CLKID_TS_DIV			139
>>> +#define CLKID_SPIFC_SEL			140
>>> +#define CLKID_SPIFC_DIV			141
>>> +#define CLKID_SPIFC_SEL2		142
>>> +#define CLKID_USB_BUS_SEL		143
>>> +#define CLKID_USB_BUS_DIV		144
>>> +#define CLKID_SD_EMMC_SEL		145
>>> +#define CLKID_SD_EMMC_DIV		146
>>> +#define CLKID_SD_EMMC_SEL2		147
>>> +#define CLKID_PSRAM_SEL			148
>>> +#define CLKID_PSRAM_DIV			149
>>> +#define CLKID_PSRAM_SEL2		150
>>> +#define CLKID_DMC_SEL			151
>>> +#define CLKID_DMC_DIV			152
>>> +#define CLKID_DMC_SEL2			153
>>> +#define NR_CLKS				154
>>> +
>>> +#include <dt-bindings/clock/a1-clkc.h>
>>> +
>>> +#endif /* __A1_H */
>>
>> .
>>


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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-04  8:24       ` Jerome Brunet
@ 2019-11-09 11:16         ` Jian Hu
  2019-11-12 16:59           ` Jerome Brunet
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-09 11:16 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel

Hi, Jerome

Sorry for late rely

On 2019/11/4 16:24, Jerome Brunet wrote:
> 
> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Jerome
>>
>> Thanks for your review
>>
>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>
>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> The Amlogic A1 clock includes three drivers:
>>>> peripheral clocks, pll clocks, CPU clocks.
>>>> sys pll and CPU clocks will be sent in next patch.
>>>>
>>>> Unlike the previous series, there is no EE/AO domain
>>>> in A1 CLK controllers.
>>>>
>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>> ---
>>>>    drivers/clk/meson/Kconfig  |   10 +
>>>>    drivers/clk/meson/Makefile |    1 +
>>>>    drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>    drivers/clk/meson/a1-pll.h |   56 ++
>>>>    drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>>>>    drivers/clk/meson/a1.h     |  120 +++
>>>>    6 files changed, 2796 insertions(+)
>>>>    create mode 100644 drivers/clk/meson/a1-pll.c
>>>>    create mode 100644 drivers/clk/meson/a1-pll.h
>>>>    create mode 100644 drivers/clk/meson/a1.c
>>>>    create mode 100644 drivers/clk/meson/a1.h
>>>
>>> In the next version, one
>> OK, I will send a1 peripheral and pll driver in two patch.
>>>
>>>>
>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>> index dabeb43..c2809b2 100644
>>>> --- a/drivers/clk/meson/Kconfig
>>>> +++ b/drivers/clk/meson/Kconfig
>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>    	  Support for the audio clock controller on AmLogic A113D devices,
>>>>    	  aka axg, Say Y if you want audio subsystem to work.
>>>>    +config COMMON_CLK_A1
>>>> +	bool
>>>> +	depends on ARCH_MESON
>>>> +	select COMMON_CLK_MESON_REGMAP
>>>> +	select COMMON_CLK_MESON_DUALDIV
>>>> +	select COMMON_CLK_MESON_PLL
>>>> +	help
>>>> +	  Support for the clock controller on Amlogic A113L device,
>>>> +	  aka a1. Say Y if you want peripherals to work.
>>>> +
>>>>    config COMMON_CLK_G12A
>>>>    	bool
>>>>    	depends on ARCH_MESON
>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>> index 3939f21..28cbae1 100644
>>>> --- a/drivers/clk/meson/Makefile
>>>> +++ b/drivers/clk/meson/Makefile
>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>>>>      obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>    obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>
>>> So far, all the controller had there own option, I don't see why it
>>> should be different here.
>>>
>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll driver
>>>>    obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>    obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>    obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>> new file mode 100644
>>>> index 0000000..486d964
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>> @@ -0,0 +1,345 @@
>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>> + */
>>>> +
>>>> +#include <linux/platform_device.h>
>>>
>>> Hum ... looks like some things are missing here
>>>
>>> #include <linux/of_device.h>
>>> #include <linux/clk-provider.h>
>>>
>>> ?
>> #1
>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>
>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>
>> #2
>> For A1 driver, the file "linux/of_device.h" is not required.
>> It is required by meson-eeclk.c in fact.
> 
> You are using what is provided by these headers directly in this file
> If meson-eeclk ever changes, your driver breaks
> 
OK, I will add the two header file.
>>>
>>>> +#include "clk-pll.h"
>>>> +#include "meson-eeclk.h"
>>>> +#include "a1-pll.h"
>>>
>>> Alphanumeric order please
>>>
>> OK, I will change it in the next version.
>>
>>>> +
>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>> +	.data = &(struct meson_clk_pll_data){
>>>> +		.en = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>> +			.shift   = 28,
>>>> +			.width   = 1,
>>>> +		},
>>>> +		.m = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>> +			.shift   = 0,
>>>> +			.width   = 8,
>>>> +		},
>>>> +		.n = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>> +			.shift   = 10,
>>>> +			.width   = 5,
>>>> +		},
>>>> +		.frac = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
>>>> +			.shift   = 0,
>>>> +			.width   = 19,
>>>> +		},
>>>> +		.l = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>> +			.shift   = 31,
>>>> +			.width   = 1,
>>>> +		},
>>>> +		.rst = {
>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>> +			.shift   = 29,
>>>> +			.width   = 1,
>>>> +		},
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fixed_pll_dco",
>>>> +		.ops = &meson_clk_pll_ro_ops,
>>>> +		.parent_data = &(const struct clk_parent_data){
>>>> +			.fw_name = "xtal_fixpll",
>>>> +			.name = "xtal_fixpll",
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_fixed_pll = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>> +		.bit_idx = 20,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "fixed_pll",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fixed_pll_dco.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * This clock is fclk_div2/3/4's parent,
>>>> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>
>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>
>>>> +		 * It is required by the platform to operate correctly.
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>
>>> Don't blindly copy/paste comments from other drivers. There is no driver
>>> for the devices you are mentionning so the end of the comment is
>>> confusing. The 3 first lines were enough
>>>
>> OK, I will remove the confusing comments
>>
>>>> +		.flags = CLK_IS_CRITICAL,
>>>
>>> >From your comment, I understand that some child are critical, not this
>>> particular (or at least, not directly). So this can be removed AFAICT
>>>
>>> You should even need CLK_IGNORE_UNUSED for this one since the clock will
>>> already be enabled before the late_init() kicks in
>>>
>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>> +	},
>>>> +};
>>>> +
>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>> +	.min = 32,
>>>> +	.max = 64,
>>>> +};
>>>> +
>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_hifi_pll = {
>>>> +	.data = &(struct meson_clk_pll_data){
>>>> +		.en = {
>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> +			.shift   = 28,
>>>> +			.width   = 1,
>>>> +		},
>>>> +		.m = {
>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> +			.shift   = 0,
>>>> +			.width   = 8,
>>>> +		},
>>>> +		.n = {
>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> +			.shift   = 10,
>>>> +			.width   = 5,
>>>> +		},
>>>> +		.frac = {
>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>> +			.shift   = 0,
>>>> +			.width   = 19,
>>>> +		},
>>>> +		.l = {
>>>> +			.reg_off = ANACTRL_HIFIPLL_STS,
>>>> +			.shift   = 31,
>>>> +			.width   = 1,
>>>> +		},
>>>> +		.range = &a1_hifi_pll_mult_range,
>>>> +		.init_regs = a1_hifi_init_regs,
>>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>> +		.strict_sequence = true,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "hifi_pll",
>>>> +		.ops = &meson_clk_pll_ops,
>>>> +		.parent_data = &(const struct clk_parent_data){
>>>> +			.fw_name = "xtal_fixpll",
>>>> +			.name = "xtal_fixpll",
>>>
>>> Both should provided when a controller transition from the old way of
>>> describing parent to the new way. This is a new controller so it does
>>> not apply.
>> I do not understand why it does not apply, could you explain more?
> 
> Your driver is new, it is not something old transitioning from global
> name to clock in DT !
> 
>>
>> The xtal_fixpll clock is registered in another peripheral driver, If do not
>> desribe the "name" member in parent_data, "fw_name" does not work because
>> it has not been registered. the hifi_pll parent will be null in
>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>
>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
> 
> There will be an orphan yes, temporarily, until both controllers are up.
> Once both controller are up, the clock will be reparented if necessary.
> 
>>
>> So both of "fw_name" of "name" should be described.
> 
> No
> 

#1

Here, I am still confused.
 From the point of view of the phenomenon, the name in parent_data is 
required.


HIFI PLL is described like this:

	.parent_data = &(const struct clk_parent_data){
		.fw_name = "xtal_hifipll",
		.name = "xtal_hifipll"
	}

Fixed PLL is described like this:

	.parent_data = &(const struct clk_parent_data){
		.fw_name = "xtal_fixpll",
	},

After the system boot completely, run cat 
/sys/kernel/debug/clk/clk_summary, Here is the result:

# cat /sys/kernel/debug/clk/clk_summary
                  enable  prepare  protect                    duty
    clock         count   count    count  rate accuracy phase cycle
--------------------------------------------------------------------
  xtal            5        5        0    24000000    0     0  50000
     ts_div       0        0        0    24000000    0     0  50000
        ts        0        0        0    24000000    0     0  50000
     pwm_f_sel    0        0        0    24000000    0     0  50000
        pwm_f_div 0        0        0    24000000    0     0  50000
           pwm_f  0        0        0    24000000    0     0  50000
......
     xtal_syspll  0        0        0    24000000    0     0  50000
     xtal_hifipll 0        0        0    24000000    0     0  50000
        hifi_pll  0        0        0  1536000000    0     0  50000
     xtal_usb_ctrl 0        0        0    24000000   0     0  50000
     xtal_usb_phy  0        0        0    24000000   0     0  50000
     xtal_fixpll   0        0        0    24000000   0     0  50000
     xtal_clktree  0        0        0    24000000   0     0  50000
  fixed_pll_dco    1        1        0         0   0     0  50000
     fixed_pll     3        3        0         0   0     0  50000
        fclk_div7_div 0     0        0         0   0     0  50000
....

the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is right.

but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
is zero.When the name in parent_data is added, its parent is xtal_fixpll.

# cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
#
# cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
0


#2
In  ./drivers/clk/qcom/gcc-sm8150.c
For some clocks, Both fw_name and name are described in parent_data struct.

>>
>>>
>>> Same for the other occurences.
>>>
>>> Also, I think you meant xtal_hifipll
>> Yes,I will correct it.
>>>
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>> +	.mult = 1,
>>>> +	.div = 2,
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div2_div",
>>>> +		.ops = &clk_fixed_factor_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fixed_pll.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>> +		.bit_idx = 21,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div2",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fclk_div2_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * This clock is used by DDR clock in BL2 firmware
>>>> +		 * and is required by the platform to operate correctly.
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>> +	.mult = 1,
>>>> +	.div = 3,
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div3_div",
>>>> +		.ops = &clk_fixed_factor_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fixed_pll.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>> +		.bit_idx = 22,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div3",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fclk_div3_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * This clock is used by APB bus which setted in Romcode
>>>> +		 * and is required by the platform to operate correctly.
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>> +	.mult = 1,
>>>> +	.div = 5,
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div5_div",
>>>> +		.ops = &clk_fixed_factor_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fixed_pll.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>> +		.bit_idx = 23,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div5",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fclk_div5_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * This clock is used by AXI bus which setted in Romcode
>>>> +		 * and is required by the platform to operate correctly.
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>> +	.mult = 1,
>>>> +	.div = 7,
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div7_div",
>>>> +		.ops = &clk_fixed_factor_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fixed_pll.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>> +		.bit_idx = 24,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "fclk_div7",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fclk_div7_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* Array of all clocks provided by this provider */
>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>> +	.hws = {
>>>> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
>>>> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
>>>> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
>>>> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
>>>> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
>>>> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
>>>> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
>>>> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
>>>> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
>>>> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
>>>> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
>>>> +		[NR_PLL_CLKS]			= NULL,
>>>> +	},
>>>> +	.num = NR_PLL_CLKS,
>>>> +};
>>>> +
>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>> +	&a1_fixed_pll_dco,
>>>> +	&a1_fixed_pll,
>>>> +	&a1_hifi_pll,
>>>> +	&a1_fclk_div2,
>>>> +	&a1_fclk_div3,
>>>> +	&a1_fclk_div5,
>>>> +	&a1_fclk_div7,
>>>> +};
>>>> +
>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = meson_eeclkc_probe(pdev);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> This function is useless.
>>>
>> OK, I will use meson_eeclkc_probe derectly.
>>>> +
>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>> +		.regmap_clks = a1_pll_regmaps,
>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
>>>> +};
>>>> +static const struct of_device_id clkc_match_table[] = {
>>>> +	{
>>>> +		.compatible = "amlogic,a1-pll-clkc",
>>>> +		.data = &a1_pll_data
>>>> +	},
>>>> +	{ /* sentinel */ }
>>>
>>> Nitpick: don't need to write this, just write the line like this
>>>
>> OK, remove it.
>>> ' }, {}'
>>>
>>>> +};
>>>> +
>>>> +static struct platform_driver a1_driver = {
>>>> +	.probe		= meson_a1_pll_probe,
>>>> +	.driver		= {
>>>> +		.name	= "a1-pll-clkc",
>>>> +		.of_match_table = clkc_match_table,
>>>> +	},
>>>> +};
>>>> +
>>>> +builtin_platform_driver(a1_driver);
>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>> new file mode 100644
>>>> index 0000000..99ee2a9
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>> @@ -0,0 +1,56 @@
>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#ifndef __A1_PLL_H
>>>> +#define __A1_PLL_H
>>>> +
>>>> +/* PLL register offset */
>>>> +#define ANACTRL_FIXPLL_CTRL0		0x80
>>>> +#define ANACTRL_FIXPLL_CTRL1		0x84
>>>> +#define ANACTRL_FIXPLL_CTRL2		0x88
>>>> +#define ANACTRL_FIXPLL_CTRL3		0x8c
>>>> +#define ANACTRL_FIXPLL_CTRL4		0x90
>>>> +#define ANACTRL_FIXPLL_STS		0x94
>>>> +#define ANACTRL_SYSPLL_CTRL0		0x100
>>>> +#define ANACTRL_SYSPLL_CTRL1		0x104
>>>> +#define ANACTRL_SYSPLL_CTRL2		0x108
>>>> +#define ANACTRL_SYSPLL_CTRL3		0x10c
>>>> +#define ANACTRL_SYSPLL_CTRL4		0x110
>>>> +#define ANACTRL_SYSPLL_STS		0x114
>>>> +#define ANACTRL_HIFIPLL_CTRL0		0x140
>>>> +#define ANACTRL_HIFIPLL_CTRL1		0x144
>>>> +#define ANACTRL_HIFIPLL_CTRL2		0x148
>>>> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
>>>> +#define ANACTRL_HIFIPLL_CTRL4		0x150
>>>> +#define ANACTRL_HIFIPLL_STS		0x154
>>>> +#define ANACTRL_AUDDDS_CTRL0		0x180
>>>> +#define ANACTRL_AUDDDS_CTRL1		0x184
>>>> +#define ANACTRL_AUDDDS_CTRL2		0x188
>>>> +#define ANACTRL_AUDDDS_CTRL3		0x18c
>>>> +#define ANACTRL_AUDDDS_CTRL4		0x190
>>>> +#define ANACTRL_AUDDDS_STS		0x194
>>>> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
>>>> +#define ANACTRL_POR_CNTL		0x208
>>>> +
>>>> +/*
>>>> + * CLKID index values
>>>> + *
>>>> + * These indices are entirely contrived and do not map onto the hardware.
>>>> + * It has now been decided to expose everything by default in the DT header:
>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
>>>> + * to expose, such as the internal muxes and dividers of composite clocks,
>>>> + * will remain defined here.
>>>> + */
>>>> +#define CLKID_FIXED_PLL_DCO		0
>>>> +#define CLKID_FCLK_DIV2_DIV		2
>>>> +#define CLKID_FCLK_DIV3_DIV		3
>>>> +#define CLKID_FCLK_DIV5_DIV		4
>>>> +#define CLKID_FCLK_DIV7_DIV		5
>>>> +#define NR_PLL_CLKS			11
>>>> +
>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>> +
>>>> +#endif /* __A1_PLL_H */
>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>> new file mode 100644
>>>> index 0000000..86a4733
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1.c
>>>> @@ -0,0 +1,2264 @@
>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>> + */
>>>> +
>>>> +#include <linux/platform_device.h>
>>>> +#include "clk-pll.h"
>>>> +#include "clk-dualdiv.h"
>>>> +#include "meson-eeclk.h"
>>>> +#include "a1.h"
>>>
>>> Same as above
>> OK, I will change the order.
>> In fact, the clk-pll.h is not used in the current driver.
>> I will remove it.
>>>
>>>> +
>>>> +/* PLLs clock in gates, its parent is xtal */
>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = SYS_OSCIN_CTRL,
>>>> +		.bit_idx = 0,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "xtal_clktree",
>>>> +		.ops = &clk_regmap_gate_ro_ops,
>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>> +			.fw_name = "xtal",
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * switch for xtal clock
>>>> +		 * Linux should not change it at runtime
>>>> +		 */
>>>
>>> Comment not useful: it uses the Ro ops
>>>
>> OK,  remove the comments
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = SYS_OSCIN_CTRL,
>>>> +		.bit_idx = 1,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "xtal_fixpll",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>> +			.fw_name = "xtal",
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +		/*
>>>> +		 * it feeds DDR,AXI,APB bus
>>>> +		 * Linux should not change it at runtime
>>>> +		 */
>>>
>>> Again, the child are critical, not directly this clock from your
>>> comment.
>>>
>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>
>> repace as clk_regmap_gate_ro_ops
>>>> +	},
>>>> +};
>>>> +
>>
>> [ ... ]
>>
>>>> +
>>>> +/* dsp a clk */
>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>> +	{ .fw_name = "xtal", },
>>>> +	{ .fw_name = "fclk_div2", },
>>>> +	{ .fw_name = "fclk_div3", },
>>>> +	{ .fw_name = "fclk_div5", },
>>>> +	{ .fw_name = "hifi_pll", },
>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 10,
>>>> +		.table = mux_table_dsp_ab,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspa_a_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>
>>> .flags = CLK_SET_RATE_PARENT ?
>> Yes, I miss the flag.
>>>
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.shift = 0,
>>>> +		.width = 10,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspa_a_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_a_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_a = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.bit_idx = 13,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspa_a",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_a_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 26,
>>>> +		.table = mux_table_dsp_ab,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspa_b_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>
>>> .flags = CLK_SET_RATE_PARENT ?
>>>
>> Yes, I will add it.
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.shift = 16,
>>>> +		.width = 10,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspa_b_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_b_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_b = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.bit_idx = 29,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspa_b",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_b_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPA_CLK_CTRL0,
>>>> +		.mask = 0x1,
>>>> +		.shift = 15,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspa_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>> +			{ .hw = &a1_dspa_a.hw },
>>>> +			{ .hw = &a1_dspa_b.hw },
>>>> +		},
>>>> +		.num_parents = 2,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPA_CLK_EN,
>>>> +		.bit_idx = 1,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspa_en_dspa",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>
>>> Why do you need CLK_IGNORE_UNUSED ?
>>>
>> I should remove it
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPA_CLK_EN,
>>>> +		.bit_idx = 0,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspa_en_nic",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspa_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>
>>> Why do you need CLK_IGNORE_UNUSED ?
>>>
>> I should remove it
>>>> +	},
>>>> +};
>>>> +
>>>
>>> Same question and remarks applies to DSP B
>>>
>> got it
>>>> +/* dsp b clk */
>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 10,
>>>> +		.table = mux_table_dsp_ab,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspb_a_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.shift = 0,
>>>> +		.width = 10,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspb_a_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_a_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_a = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.bit_idx = 13,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspb_a",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_a_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 26,
>>>> +		.table = mux_table_dsp_ab,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspb_b_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.shift = 16,
>>>> +		.width = 10,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspb_b_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_b_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_b = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.bit_idx = 29,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspb_b",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_b_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DSPB_CLK_CTRL0,
>>>> +		.mask = 0x1,
>>>> +		.shift = 15,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dspb_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
>>>> +		},
>>>> +		.num_parents = 2,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPB_CLK_EN,
>>>> +		.bit_idx = 1,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspb_en_dspb",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DSPB_CLK_EN,
>>>> +		.bit_idx = 0,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dspb_en_nic",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dspb_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* 12M/24M clock */
>>>> +static struct clk_regmap a1_24m = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = CLK12_24_CTRL,
>>>> +		.bit_idx = 11,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "24m",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>> +			.fw_name = "xtal",
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +	},
>>>> +};
>>>> +
>>
>> [ ... ]
>>
>>>> +static struct clk_regmap a1_saradc_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 9,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "saradc_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>> +			{ .fw_name = "xtal", },
>>>> +			{ .hw = &a1_sys_clk.hw, },
>>>> +		},
>>>> +		.num_parents = 2,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_saradc_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>> +		.shift = 0,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "saradc_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_saradc_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_saradc_clk = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>> +		.bit_idx = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "saradc_clk",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_saradc_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* pwm a/b/c/d parent data */
>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>> +	{ .fw_name = "xtal", },
>>>> +	{ .hw = &a1_sys_clk.hw },
>>>> +};
>>>
>>> Looks like the same as SAR ADC
>>>
>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>> +
>>>> +/* pwm a clk */
>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 9,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_a_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.shift = 0,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_a_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_a_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_a = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.bit_idx = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_a",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_a_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * The CPU working voltage is controlled by pwm_a
>>>> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>> +		 * to avoid changing at runtime.
>>>                                       ^ it
>>>
>>>> +		 * and is required by the platform to operate correctly.
>>>                      "blabla. And" is strange
>>>
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>
>>> This only skips the late_init() disable of unused clocks
>>>
>>> Be aware that this is not fool-proof. If at any time a driver enable
>>> then disable the clock, the clock will be disable and I guess your
>>> platform will die if this provides the CPU voltage.
>> OK, CLK_IS_CRITICAL is better.
>>>
>>>> +	},
>>>> +};
>>>> +
>>>> +/* pwm b clk */
>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 25,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_b_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.shift = 16,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_b_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_b_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_b = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>> +		.bit_idx = 24,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_b",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_b_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* pwm c clk */
>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 9,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_c_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.shift = 0,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_c_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_c_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_c = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.bit_idx = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_c",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_c_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* pwm d clk */
>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 25,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_d_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.shift = 16,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_d_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_d_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_d = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>> +		.bit_idx = 24,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_d",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_d_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>> +	{ .fw_name = "xtal", },
>>>> +	{ .hw = &a1_sys_clk.hw },
>>>> +	{ .fw_name = "fclk_div5", },
>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>> +};
>>>> +
>>>> +/* pwm e clk */
>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.mask = 0x3,
>>>> +		.shift = 9,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_e_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_ef_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.shift = 0,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_e_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_e_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_e = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.bit_idx = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_e",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_e_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* pwm f clk */
>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.mask = 0x3,
>>>> +		.shift = 25,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_f_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = pwm_ef_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.shift = 16,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "pwm_f_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_f_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_pwm_f = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>> +		.bit_idx = 24,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "pwm_f",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_pwm_f_div.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>
>> [ ... ]
>>
>>>> +
>>>> +/* dmc clk */
>>>> +static struct clk_regmap a1_dmc_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DMC_CLK_CTRL,
>>>> +		.mask = 0x3,
>>>> +		.shift = 9,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dmc_sel",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = sd_emmc_parents,
>>>> +		.num_parents = 4,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dmc_div = {
>>>> +	.data = &(struct clk_regmap_div_data){
>>>> +		.offset = DMC_CLK_CTRL,
>>>> +		.shift = 0,
>>>> +		.width = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dmc_div",
>>>> +		.ops = &clk_regmap_divider_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dmc_sel.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = DMC_CLK_CTRL,
>>>> +		.mask = 0x1,
>>>> +		.shift = 15,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "dmc_sel2",
>>>> +		.ops = &clk_regmap_mux_ops,
>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>> +			{ .hw = &a1_dmc_div.hw },
>>>> +			{ .fw_name = "xtal", },
>>>> +		},
>>>> +		.num_parents = 2,
>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_dmc = {
>>>> +	.data = &(struct clk_regmap_gate_data){
>>>> +		.offset = DMC_CLK_CTRL,
>>>> +		.bit_idx = 8,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data) {
>>>> +		.name = "dmc",
>>>> +		.ops = &clk_regmap_gate_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_dmc_sel2.hw
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		/*
>>>> +		 * This clock is used by DDR clock which setted in BL2
>>>> +		 * and is required by the platform to operate correctly.
>>>> +		 * Until the following condition are met, we need this clock to
>>>> +		 * be marked as critical:
>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>> +		 *    clock stays on until the proper driver comes along
>>>> +		 */
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>
>>> Should you put all this DMC stuff in RO until you got a driver for it ?
>> OK, replace as clk_regmap_gate_ro_ops
>>>
>> [ ... ]
>>>> +
>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = meson_eeclkc_probe(pdev);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	return 0;
>>>> +}
>>>
>>> Again this function is function is useless and it makes me wonder if you
>>> should really be using meson_eeclkc_probe()
>>>
>>> This makes you use syscon which is not correct unless you have a good
>>> reason ?
>>>
>> If it can not use the meson_eeclkc_probe(), I will realize a probe function
>> which is mostly duplicate with meson_eeclkc_probe() except
>> "syscon_node_to_regmap"
>>
>> Maybe another common probe function and a new file are required for A1
>> three drivers? (include the CPU clock driver)
> 
> Maybe
> 
I will add a new function base on meson-eeclk.c
>>
>> Or using meson_eeclkc_probe is more easier?
> 
> It is not question of easiness, but correctness.
> 
>>
>>> Is there anything but clocks and resets in these register region ?
>> No, there is only clocks in the register region.
>> the same does the PLL register region.
> 
> Then there is no reason to use syscon for those drivers
>Add a new probe function for A1
>>>
>>>> +
>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>> +		.regmap_clks = a1_periphs_regmaps,
>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>> +};
>>>> +static const struct of_device_id clkc_match_table[] = {
>>>> +	{
>>>> +		.compatible = "amlogic,a1-periphs-clkc",
>>>> +		.data = &a1_periphs_data
>>>> +	},
>>>> +	{ /* sentinel */ }
>>>> +};
>>>> +
>>>> +static struct platform_driver a1_driver = {
>>>> +	.probe		= meson_a1_periphs_probe,
>>>> +	.driver		= {
>>>> +		.name	= "a1-periphs-clkc",
>>>> +		.of_match_table = clkc_match_table,
>>>> +	},
>>>> +};
>>>> +
>>>> +builtin_platform_driver(a1_driver);
>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>> new file mode 100644
>>>> index 0000000..1ae5e04
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1.h
>>>> @@ -0,0 +1,120 @@
>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#ifndef __A1_H
>>>> +#define __A1_H
>>>> +
>>>> +/* peripheral clock controller register offset */
>>>> +#define SYS_OSCIN_CTRL			0x0
>>>> +#define RTC_BY_OSCIN_CTRL0		0x4
>>>> +#define RTC_BY_OSCIN_CTRL1		0x8
>>>> +#define RTC_CTRL			0xc
>>>> +#define SYS_CLK_CTRL0			0x10
>>>> +#define AXI_CLK_CTRL0			0x14
>>>> +#define SYS_CLK_EN0			0x1c
>>>> +#define SYS_CLK_EN1			0x20
>>>> +#define AXI_CLK_EN			0x24
>>>> +#define DSPA_CLK_EN			0x28
>>>> +#define DSPB_CLK_EN			0x2c
>>>> +#define DSPA_CLK_CTRL0			0x30
>>>> +#define DSPB_CLK_CTRL0			0x34
>>>> +#define CLK12_24_CTRL			0x38
>>>> +#define GEN_CLK_CTRL			0x3c
>>>> +#define TIMESTAMP_CTRL0			0x40
>>>> +#define TIMESTAMP_CTRL1			0x44
>>>> +#define TIMESTAMP_CTRL2			0x48
>>>> +#define TIMESTAMP_VAL0			0x4c
>>>> +#define TIMESTAMP_VAL1			0x50
>>>> +#define TIMEBASE_CTRL0			0x54
>>>> +#define TIMEBASE_CTRL1			0x58
>>>> +#define SAR_ADC_CLK_CTRL		0xc0
>>>> +#define PWM_CLK_AB_CTRL			0xc4
>>>> +#define PWM_CLK_CD_CTRL			0xc8
>>>> +#define PWM_CLK_EF_CTRL			0xcc
>>>> +#define SPICC_CLK_CTRL			0xd0
>>>> +#define TS_CLK_CTRL			0xd4
>>>> +#define SPIFC_CLK_CTRL			0xd8
>>>> +#define USB_BUSCLK_CTRL			0xdc
>>>> +#define SD_EMMC_CLK_CTRL		0xe0
>>>> +#define CECA_CLK_CTRL0			0xe4
>>>> +#define CECA_CLK_CTRL1			0xe8
>>>> +#define CECB_CLK_CTRL0			0xec
>>>> +#define CECB_CLK_CTRL1			0xf0
>>>> +#define PSRAM_CLK_CTRL			0xf4
>>>> +#define DMC_CLK_CTRL			0xf8
>>>> +#define FCLK_DIV1_SEL			0xfc
>>>> +#define TST_CTRL			0x100
>>>> +
>>>> +#define CLKID_XTAL_CLKTREE		0
>>>> +#define CLKID_SYS_A_SEL			89
>>>> +#define CLKID_SYS_A_DIV			90
>>>> +#define CLKID_SYS_A			91
>>>> +#define CLKID_SYS_B_SEL			92
>>>> +#define CLKID_SYS_B_DIV			93
>>>> +#define CLKID_SYS_B			94
>>>> +#define CLKID_DSPA_A_SEL		95
>>>> +#define CLKID_DSPA_A_DIV		96
>>>> +#define CLKID_DSPA_A			97
>>>> +#define CLKID_DSPA_B_SEL		98
>>>> +#define CLKID_DSPA_B_DIV		99
>>>> +#define CLKID_DSPA_B			100
>>>> +#define CLKID_DSPB_A_SEL		101
>>>> +#define CLKID_DSPB_A_DIV		102
>>>> +#define CLKID_DSPB_A			103
>>>> +#define CLKID_DSPB_B_SEL		104
>>>> +#define CLKID_DSPB_B_DIV		105
>>>> +#define CLKID_DSPB_B			106
>>>> +#define CLKID_RTC_32K_CLKIN		107
>>>> +#define CLKID_RTC_32K_DIV		108
>>>> +#define CLKID_RTC_32K_XTAL		109
>>>> +#define CLKID_RTC_32K_SEL		110
>>>> +#define CLKID_CECB_32K_CLKIN		111
>>>> +#define CLKID_CECB_32K_DIV		112
>>>> +#define CLKID_CECB_32K_SEL_PRE		113
>>>> +#define CLKID_CECB_32K_SEL		114
>>>> +#define CLKID_CECA_32K_CLKIN		115
>>>> +#define CLKID_CECA_32K_DIV		116
>>>> +#define CLKID_CECA_32K_SEL_PRE		117
>>>> +#define CLKID_CECA_32K_SEL		118
>>>> +#define CLKID_DIV2_PRE			119
>>>> +#define CLKID_24M_DIV2			120
>>>> +#define CLKID_GEN_SEL			121
>>>> +#define CLKID_GEN_DIV			122
>>>> +#define CLKID_SARADC_DIV		123
>>>> +#define CLKID_PWM_A_SEL			124
>>>> +#define CLKID_PWM_A_DIV			125
>>>> +#define CLKID_PWM_B_SEL			126
>>>> +#define CLKID_PWM_B_DIV			127
>>>> +#define CLKID_PWM_C_SEL			128
>>>> +#define CLKID_PWM_C_DIV			129
>>>> +#define CLKID_PWM_D_SEL			130
>>>> +#define CLKID_PWM_D_DIV			131
>>>> +#define CLKID_PWM_E_SEL			132
>>>> +#define CLKID_PWM_E_DIV			133
>>>> +#define CLKID_PWM_F_SEL			134
>>>> +#define CLKID_PWM_F_DIV			135
>>>> +#define CLKID_SPICC_SEL			136
>>>> +#define CLKID_SPICC_DIV			137
>>>> +#define CLKID_SPICC_SEL2		138
>>>> +#define CLKID_TS_DIV			139
>>>> +#define CLKID_SPIFC_SEL			140
>>>> +#define CLKID_SPIFC_DIV			141
>>>> +#define CLKID_SPIFC_SEL2		142
>>>> +#define CLKID_USB_BUS_SEL		143
>>>> +#define CLKID_USB_BUS_DIV		144
>>>> +#define CLKID_SD_EMMC_SEL		145
>>>> +#define CLKID_SD_EMMC_DIV		146
>>>> +#define CLKID_SD_EMMC_SEL2		147
>>>> +#define CLKID_PSRAM_SEL			148
>>>> +#define CLKID_PSRAM_DIV			149
>>>> +#define CLKID_PSRAM_SEL2		150
>>>> +#define CLKID_DMC_SEL			151
>>>> +#define CLKID_DMC_DIV			152
>>>> +#define CLKID_DMC_SEL2			153
>>>> +#define NR_CLKS				154
>>>> +
>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>> +
>>>> +#endif /* __A1_H */
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-09 11:16         ` Jian Hu
@ 2019-11-12 16:59           ` Jerome Brunet
  2019-11-13 14:21             ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-11-12 16:59 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Sat 09 Nov 2019 at 12:16, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Jerome
>
> Sorry for late rely
>
> On 2019/11/4 16:24, Jerome Brunet wrote:
>>
>> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> Hi, Jerome
>>>
>>> Thanks for your review
>>>
>>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>>
>>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> The Amlogic A1 clock includes three drivers:
>>>>> peripheral clocks, pll clocks, CPU clocks.
>>>>> sys pll and CPU clocks will be sent in next patch.
>>>>>
>>>>> Unlike the previous series, there is no EE/AO domain
>>>>> in A1 CLK controllers.
>>>>>
>>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>>> ---
>>>>>    drivers/clk/meson/Kconfig  |   10 +
>>>>>    drivers/clk/meson/Makefile |    1 +
>>>>>    drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>>    drivers/clk/meson/a1-pll.h |   56 ++
>>>>>    drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>>>>>    drivers/clk/meson/a1.h     |  120 +++
>>>>>    6 files changed, 2796 insertions(+)
>>>>>    create mode 100644 drivers/clk/meson/a1-pll.c
>>>>>    create mode 100644 drivers/clk/meson/a1-pll.h
>>>>>    create mode 100644 drivers/clk/meson/a1.c
>>>>>    create mode 100644 drivers/clk/meson/a1.h
>>>>
>>>> In the next version, one
>>> OK, I will send a1 peripheral and pll driver in two patch.
>>>>
>>>>>
>>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>>> index dabeb43..c2809b2 100644
>>>>> --- a/drivers/clk/meson/Kconfig
>>>>> +++ b/drivers/clk/meson/Kconfig
>>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>>    	  Support for the audio clock controller on AmLogic A113D devices,
>>>>>    	  aka axg, Say Y if you want audio subsystem to work.
>>>>>    +config COMMON_CLK_A1
>>>>> +	bool
>>>>> +	depends on ARCH_MESON
>>>>> +	select COMMON_CLK_MESON_REGMAP
>>>>> +	select COMMON_CLK_MESON_DUALDIV
>>>>> +	select COMMON_CLK_MESON_PLL
>>>>> +	help
>>>>> +	  Support for the clock controller on Amlogic A113L device,
>>>>> +	  aka a1. Say Y if you want peripherals to work.
>>>>> +
>>>>>    config COMMON_CLK_G12A
>>>>>    	bool
>>>>>    	depends on ARCH_MESON
>>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>>> index 3939f21..28cbae1 100644
>>>>> --- a/drivers/clk/meson/Makefile
>>>>> +++ b/drivers/clk/meson/Makefile
>>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>>>>>      obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>>    obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>>
>>>> So far, all the controller had there own option, I don't see why it
>>>> should be different here.
>>>>
>>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll driver
>>>>>    obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>>    obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>>    obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>>> new file mode 100644
>>>>> index 0000000..486d964
>>>>> --- /dev/null
>>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>>> @@ -0,0 +1,345 @@
>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>> +/*
>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>> + */
>>>>> +
>>>>> +#include <linux/platform_device.h>
>>>>
>>>> Hum ... looks like some things are missing here
>>>>
>>>> #include <linux/of_device.h>
>>>> #include <linux/clk-provider.h>
>>>>
>>>> ?
>>> #1
>>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>>
>>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>>
>>> #2
>>> For A1 driver, the file "linux/of_device.h" is not required.
>>> It is required by meson-eeclk.c in fact.
>>
>> You are using what is provided by these headers directly in this file
>> If meson-eeclk ever changes, your driver breaks
>>
> OK, I will add the two header file.
>>>>
>>>>> +#include "clk-pll.h"
>>>>> +#include "meson-eeclk.h"
>>>>> +#include "a1-pll.h"
>>>>
>>>> Alphanumeric order please
>>>>
>>> OK, I will change it in the next version.
>>>
>>>>> +
>>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>>> +	.data = &(struct meson_clk_pll_data){
>>>>> +		.en = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>> +			.shift   = 28,
>>>>> +			.width   = 1,
>>>>> +		},
>>>>> +		.m = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>> +			.shift   = 0,
>>>>> +			.width   = 8,
>>>>> +		},
>>>>> +		.n = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>> +			.shift   = 10,
>>>>> +			.width   = 5,
>>>>> +		},
>>>>> +		.frac = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
>>>>> +			.shift   = 0,
>>>>> +			.width   = 19,
>>>>> +		},
>>>>> +		.l = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>> +			.shift   = 31,
>>>>> +			.width   = 1,
>>>>> +		},
>>>>> +		.rst = {
>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>> +			.shift   = 29,
>>>>> +			.width   = 1,
>>>>> +		},
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fixed_pll_dco",
>>>>> +		.ops = &meson_clk_pll_ro_ops,
>>>>> +		.parent_data = &(const struct clk_parent_data){
>>>>> +			.fw_name = "xtal_fixpll",
>>>>> +			.name = "xtal_fixpll",
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_fixed_pll = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>> +		.bit_idx = 20,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "fixed_pll",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fixed_pll_dco.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * This clock is fclk_div2/3/4's parent,
>>>>> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>>
>>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>>
>>>>> +		 * It is required by the platform to operate correctly.
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>
>>>> Don't blindly copy/paste comments from other drivers. There is no driver
>>>> for the devices you are mentionning so the end of the comment is
>>>> confusing. The 3 first lines were enough
>>>>
>>> OK, I will remove the confusing comments
>>>
>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>
>>>> >From your comment, I understand that some child are critical, not this
>>>> particular (or at least, not directly). So this can be removed AFAICT
>>>>
>>>> You should even need CLK_IGNORE_UNUSED for this one since the clock will
>>>> already be enabled before the late_init() kicks in
>>>>
>>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>>> +	.min = 32,
>>>>> +	.max = 64,
>>>>> +};
>>>>> +
>>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_hifi_pll = {
>>>>> +	.data = &(struct meson_clk_pll_data){
>>>>> +		.en = {
>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>> +			.shift   = 28,
>>>>> +			.width   = 1,
>>>>> +		},
>>>>> +		.m = {
>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>> +			.shift   = 0,
>>>>> +			.width   = 8,
>>>>> +		},
>>>>> +		.n = {
>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>> +			.shift   = 10,
>>>>> +			.width   = 5,
>>>>> +		},
>>>>> +		.frac = {
>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>>> +			.shift   = 0,
>>>>> +			.width   = 19,
>>>>> +		},
>>>>> +		.l = {
>>>>> +			.reg_off = ANACTRL_HIFIPLL_STS,
>>>>> +			.shift   = 31,
>>>>> +			.width   = 1,
>>>>> +		},
>>>>> +		.range = &a1_hifi_pll_mult_range,
>>>>> +		.init_regs = a1_hifi_init_regs,
>>>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>> +		.strict_sequence = true,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "hifi_pll",
>>>>> +		.ops = &meson_clk_pll_ops,
>>>>> +		.parent_data = &(const struct clk_parent_data){
>>>>> +			.fw_name = "xtal_fixpll",
>>>>> +			.name = "xtal_fixpll",
>>>>
>>>> Both should provided when a controller transition from the old way of
>>>> describing parent to the new way. This is a new controller so it does
>>>> not apply.
>>> I do not understand why it does not apply, could you explain more?
>>
>> Your driver is new, it is not something old transitioning from global
>> name to clock in DT !
>>
>>>
>>> The xtal_fixpll clock is registered in another peripheral driver, If do not
>>> desribe the "name" member in parent_data, "fw_name" does not work because
>>> it has not been registered. the hifi_pll parent will be null in
>>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>>
>>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
>>
>> There will be an orphan yes, temporarily, until both controllers are up.
>> Once both controller are up, the clock will be reparented if necessary.
>>
>>>
>>> So both of "fw_name" of "name" should be described.
>>
>> No
>>
>
> #1
>
> Here, I am still confused.
> From the point of view of the phenomenon, the name in parent_data is
> required.
>
>
> HIFI PLL is described like this:
>
> 	.parent_data = &(const struct clk_parent_data){
> 		.fw_name = "xtal_hifipll",
> 		.name = "xtal_hifipll"
> 	}
>
> Fixed PLL is described like this:
>
> 	.parent_data = &(const struct clk_parent_data){
> 		.fw_name = "xtal_fixpll",
> 	},
>
> After the system boot completely, run cat
> /sys/kernel/debug/clk/clk_summary, Here is the result:
>
> # cat /sys/kernel/debug/clk/clk_summary
>                  enable  prepare  protect                    duty
>    clock         count   count    count  rate accuracy phase cycle
> --------------------------------------------------------------------
>  xtal            5        5        0    24000000    0     0  50000
>     ts_div       0        0        0    24000000    0     0  50000
>        ts        0        0        0    24000000    0     0  50000
>     pwm_f_sel    0        0        0    24000000    0     0  50000
>        pwm_f_div 0        0        0    24000000    0     0  50000
>           pwm_f  0        0        0    24000000    0     0  50000
> ......
>     xtal_syspll  0        0        0    24000000    0     0  50000
>     xtal_hifipll 0        0        0    24000000    0     0  50000
>        hifi_pll  0        0        0  1536000000    0     0  50000
>     xtal_usb_ctrl 0        0        0    24000000   0     0  50000
>     xtal_usb_phy  0        0        0    24000000   0     0  50000
>     xtal_fixpll   0        0        0    24000000   0     0  50000
>     xtal_clktree  0        0        0    24000000   0     0  50000
>  fixed_pll_dco    1        1        0         0   0     0  50000

This means that CCF what not able to resolve the parent.
Either:
* you've made a mistake somewhere
* There is bug in CCF when the parent device is not available at probe
time, the clock is not properly reparented

Either way, you'll have to debug a bit more

>     fixed_pll     3        3        0         0   0     0  50000
>        fclk_div7_div 0     0        0         0   0     0  50000
> ....
>
> the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is right.
>
> but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
> is zero.When the name in parent_data is added, its parent is xtal_fixpll.
>
> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
> #
> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
> 0
>
>
> #2
> In  ./drivers/clk/qcom/gcc-sm8150.c
> For some clocks, Both fw_name and name are described in parent_data
> struct.

Those are being migrated to DT description which means that we don't
know if the DT will the correct description

In this case the clock framework will first try DT and if DT does
provide this fw_name, it will fallback to the legacy name.

This is not your case as this is a new platform for which we know the DT
name exist.

>
>>>
>>>>
>>>> Same for the other occurences.
>>>>
>>>> Also, I think you meant xtal_hifipll
>>> Yes,I will correct it.
>>>>
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>>> +	.mult = 1,
>>>>> +	.div = 2,
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div2_div",
>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fixed_pll.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>> +		.bit_idx = 21,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div2",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fclk_div2_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * This clock is used by DDR clock in BL2 firmware
>>>>> +		 * and is required by the platform to operate correctly.
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>>> +	.mult = 1,
>>>>> +	.div = 3,
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div3_div",
>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fixed_pll.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>> +		.bit_idx = 22,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div3",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fclk_div3_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * This clock is used by APB bus which setted in Romcode
>>>>> +		 * and is required by the platform to operate correctly.
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>>> +	.mult = 1,
>>>>> +	.div = 5,
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div5_div",
>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fixed_pll.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>> +		.bit_idx = 23,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div5",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fclk_div5_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * This clock is used by AXI bus which setted in Romcode
>>>>> +		 * and is required by the platform to operate correctly.
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>>> +	.mult = 1,
>>>>> +	.div = 7,
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div7_div",
>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fixed_pll.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>> +		.bit_idx = 24,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "fclk_div7",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_fclk_div7_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* Array of all clocks provided by this provider */
>>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>>> +	.hws = {
>>>>> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
>>>>> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
>>>>> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
>>>>> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
>>>>> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
>>>>> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
>>>>> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
>>>>> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
>>>>> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
>>>>> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
>>>>> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
>>>>> +		[NR_PLL_CLKS]			= NULL,
>>>>> +	},
>>>>> +	.num = NR_PLL_CLKS,
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>>> +	&a1_fixed_pll_dco,
>>>>> +	&a1_fixed_pll,
>>>>> +	&a1_hifi_pll,
>>>>> +	&a1_fclk_div2,
>>>>> +	&a1_fclk_div3,
>>>>> +	&a1_fclk_div5,
>>>>> +	&a1_fclk_div7,
>>>>> +};
>>>>> +
>>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>>> +{
>>>>> +	int ret;
>>>>> +
>>>>> +	ret = meson_eeclkc_probe(pdev);
>>>>> +	if (ret)
>>>>> +		return ret;
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>
>>>> This function is useless.
>>>>
>>> OK, I will use meson_eeclkc_probe derectly.
>>>>> +
>>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>>> +		.regmap_clks = a1_pll_regmaps,
>>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>>> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
>>>>> +};
>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>> +	{
>>>>> +		.compatible = "amlogic,a1-pll-clkc",
>>>>> +		.data = &a1_pll_data
>>>>> +	},
>>>>> +	{ /* sentinel */ }
>>>>
>>>> Nitpick: don't need to write this, just write the line like this
>>>>
>>> OK, remove it.
>>>> ' }, {}'
>>>>
>>>>> +};
>>>>> +
>>>>> +static struct platform_driver a1_driver = {
>>>>> +	.probe		= meson_a1_pll_probe,
>>>>> +	.driver		= {
>>>>> +		.name	= "a1-pll-clkc",
>>>>> +		.of_match_table = clkc_match_table,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +builtin_platform_driver(a1_driver);
>>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>>> new file mode 100644
>>>>> index 0000000..99ee2a9
>>>>> --- /dev/null
>>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>>> @@ -0,0 +1,56 @@
>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>> +/*
>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>> + */
>>>>> +
>>>>> +#ifndef __A1_PLL_H
>>>>> +#define __A1_PLL_H
>>>>> +
>>>>> +/* PLL register offset */
>>>>> +#define ANACTRL_FIXPLL_CTRL0		0x80
>>>>> +#define ANACTRL_FIXPLL_CTRL1		0x84
>>>>> +#define ANACTRL_FIXPLL_CTRL2		0x88
>>>>> +#define ANACTRL_FIXPLL_CTRL3		0x8c
>>>>> +#define ANACTRL_FIXPLL_CTRL4		0x90
>>>>> +#define ANACTRL_FIXPLL_STS		0x94
>>>>> +#define ANACTRL_SYSPLL_CTRL0		0x100
>>>>> +#define ANACTRL_SYSPLL_CTRL1		0x104
>>>>> +#define ANACTRL_SYSPLL_CTRL2		0x108
>>>>> +#define ANACTRL_SYSPLL_CTRL3		0x10c
>>>>> +#define ANACTRL_SYSPLL_CTRL4		0x110
>>>>> +#define ANACTRL_SYSPLL_STS		0x114
>>>>> +#define ANACTRL_HIFIPLL_CTRL0		0x140
>>>>> +#define ANACTRL_HIFIPLL_CTRL1		0x144
>>>>> +#define ANACTRL_HIFIPLL_CTRL2		0x148
>>>>> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
>>>>> +#define ANACTRL_HIFIPLL_CTRL4		0x150
>>>>> +#define ANACTRL_HIFIPLL_STS		0x154
>>>>> +#define ANACTRL_AUDDDS_CTRL0		0x180
>>>>> +#define ANACTRL_AUDDDS_CTRL1		0x184
>>>>> +#define ANACTRL_AUDDDS_CTRL2		0x188
>>>>> +#define ANACTRL_AUDDDS_CTRL3		0x18c
>>>>> +#define ANACTRL_AUDDDS_CTRL4		0x190
>>>>> +#define ANACTRL_AUDDDS_STS		0x194
>>>>> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
>>>>> +#define ANACTRL_POR_CNTL		0x208
>>>>> +
>>>>> +/*
>>>>> + * CLKID index values
>>>>> + *
>>>>> + * These indices are entirely contrived and do not map onto the hardware.
>>>>> + * It has now been decided to expose everything by default in the DT header:
>>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
>>>>> + * to expose, such as the internal muxes and dividers of composite clocks,
>>>>> + * will remain defined here.
>>>>> + */
>>>>> +#define CLKID_FIXED_PLL_DCO		0
>>>>> +#define CLKID_FCLK_DIV2_DIV		2
>>>>> +#define CLKID_FCLK_DIV3_DIV		3
>>>>> +#define CLKID_FCLK_DIV5_DIV		4
>>>>> +#define CLKID_FCLK_DIV7_DIV		5
>>>>> +#define NR_PLL_CLKS			11
>>>>> +
>>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>>> +
>>>>> +#endif /* __A1_PLL_H */
>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>> new file mode 100644
>>>>> index 0000000..86a4733
>>>>> --- /dev/null
>>>>> +++ b/drivers/clk/meson/a1.c
>>>>> @@ -0,0 +1,2264 @@
>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>> +/*
>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>> + */
>>>>> +
>>>>> +#include <linux/platform_device.h>
>>>>> +#include "clk-pll.h"
>>>>> +#include "clk-dualdiv.h"
>>>>> +#include "meson-eeclk.h"
>>>>> +#include "a1.h"
>>>>
>>>> Same as above
>>> OK, I will change the order.
>>> In fact, the clk-pll.h is not used in the current driver.
>>> I will remove it.
>>>>
>>>>> +
>>>>> +/* PLLs clock in gates, its parent is xtal */
>>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = SYS_OSCIN_CTRL,
>>>>> +		.bit_idx = 0,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "xtal_clktree",
>>>>> +		.ops = &clk_regmap_gate_ro_ops,
>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>> +			.fw_name = "xtal",
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * switch for xtal clock
>>>>> +		 * Linux should not change it at runtime
>>>>> +		 */
>>>>
>>>> Comment not useful: it uses the Ro ops
>>>>
>>> OK,  remove the comments
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = SYS_OSCIN_CTRL,
>>>>> +		.bit_idx = 1,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "xtal_fixpll",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>> +			.fw_name = "xtal",
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>> +		/*
>>>>> +		 * it feeds DDR,AXI,APB bus
>>>>> +		 * Linux should not change it at runtime
>>>>> +		 */
>>>>
>>>> Again, the child are critical, not directly this clock from your
>>>> comment.
>>>>
>>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>>
>>> repace as clk_regmap_gate_ro_ops
>>>>> +	},
>>>>> +};
>>>>> +
>>>
>>> [ ... ]
>>>
>>>>> +
>>>>> +/* dsp a clk */
>>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>>> +	{ .fw_name = "xtal", },
>>>>> +	{ .fw_name = "fclk_div2", },
>>>>> +	{ .fw_name = "fclk_div3", },
>>>>> +	{ .fw_name = "fclk_div5", },
>>>>> +	{ .fw_name = "hifi_pll", },
>>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.mask = 0x7,
>>>>> +		.shift = 10,
>>>>> +		.table = mux_table_dsp_ab,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspa_a_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>
>>>> .flags = CLK_SET_RATE_PARENT ?
>>> Yes, I miss the flag.
>>>>
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.shift = 0,
>>>>> +		.width = 10,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspa_a_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_a_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_a = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.bit_idx = 13,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspa_a",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_a_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.mask = 0x7,
>>>>> +		.shift = 26,
>>>>> +		.table = mux_table_dsp_ab,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspa_b_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>
>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>
>>> Yes, I will add it.
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.shift = 16,
>>>>> +		.width = 10,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspa_b_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_b_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_b = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.bit_idx = 29,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspa_b",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_b_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 15,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspa_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>> +			{ .hw = &a1_dspa_a.hw },
>>>>> +			{ .hw = &a1_dspa_b.hw },
>>>>> +		},
>>>>> +		.num_parents = 2,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPA_CLK_EN,
>>>>> +		.bit_idx = 1,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspa_en_dspa",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>
>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>
>>> I should remove it
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPA_CLK_EN,
>>>>> +		.bit_idx = 0,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspa_en_nic",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspa_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>
>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>
>>> I should remove it
>>>>> +	},
>>>>> +};
>>>>> +
>>>>
>>>> Same question and remarks applies to DSP B
>>>>
>>> got it
>>>>> +/* dsp b clk */
>>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.mask = 0x7,
>>>>> +		.shift = 10,
>>>>> +		.table = mux_table_dsp_ab,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspb_a_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.shift = 0,
>>>>> +		.width = 10,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspb_a_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_a_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_a = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.bit_idx = 13,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspb_a",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_a_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.mask = 0x7,
>>>>> +		.shift = 26,
>>>>> +		.table = mux_table_dsp_ab,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspb_b_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.shift = 16,
>>>>> +		.width = 10,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspb_b_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_b_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_b = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.bit_idx = 29,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspb_b",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_b_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 15,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dspb_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
>>>>> +		},
>>>>> +		.num_parents = 2,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPB_CLK_EN,
>>>>> +		.bit_idx = 1,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspb_en_dspb",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DSPB_CLK_EN,
>>>>> +		.bit_idx = 0,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dspb_en_nic",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dspb_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* 12M/24M clock */
>>>>> +static struct clk_regmap a1_24m = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = CLK12_24_CTRL,
>>>>> +		.bit_idx = 11,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "24m",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>> +			.fw_name = "xtal",
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +	},
>>>>> +};
>>>>> +
>>>
>>> [ ... ]
>>>
>>>>> +static struct clk_regmap a1_saradc_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 9,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "saradc_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>> +			{ .fw_name = "xtal", },
>>>>> +			{ .hw = &a1_sys_clk.hw, },
>>>>> +		},
>>>>> +		.num_parents = 2,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_saradc_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>> +		.shift = 0,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "saradc_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_saradc_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_saradc_clk = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>> +		.bit_idx = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "saradc_clk",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_saradc_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* pwm a/b/c/d parent data */
>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>> +	{ .fw_name = "xtal", },
>>>>> +	{ .hw = &a1_sys_clk.hw },
>>>>> +};
>>>>
>>>> Looks like the same as SAR ADC
>>>>
>>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>>> +
>>>>> +/* pwm a clk */
>>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 9,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_a_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.shift = 0,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_a_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_a_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_a = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.bit_idx = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_a",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_a_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * The CPU working voltage is controlled by pwm_a
>>>>> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>>> +		 * to avoid changing at runtime.
>>>>                                       ^ it
>>>>
>>>>> +		 * and is required by the platform to operate correctly.
>>>>                      "blabla. And" is strange
>>>>
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>
>>>> This only skips the late_init() disable of unused clocks
>>>>
>>>> Be aware that this is not fool-proof. If at any time a driver enable
>>>> then disable the clock, the clock will be disable and I guess your
>>>> platform will die if this provides the CPU voltage.
>>> OK, CLK_IS_CRITICAL is better.
>>>>
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* pwm b clk */
>>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 25,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_b_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.shift = 16,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_b_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_b_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_b = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>> +		.bit_idx = 24,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_b",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_b_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* pwm c clk */
>>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 9,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_c_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.shift = 0,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_c_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_c_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_c = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.bit_idx = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_c",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_c_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* pwm d clk */
>>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 25,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_d_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.shift = 16,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_d_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_d_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_d = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>> +		.bit_idx = 24,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_d",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_d_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>>> +	{ .fw_name = "xtal", },
>>>>> +	{ .hw = &a1_sys_clk.hw },
>>>>> +	{ .fw_name = "fclk_div5", },
>>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>>> +};
>>>>> +
>>>>> +/* pwm e clk */
>>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.mask = 0x3,
>>>>> +		.shift = 9,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_e_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_ef_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.shift = 0,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_e_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_e_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_e = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.bit_idx = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_e",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_e_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +/* pwm f clk */
>>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.mask = 0x3,
>>>>> +		.shift = 25,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_f_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = pwm_ef_parent_data,
>>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.shift = 16,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "pwm_f_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_f_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_pwm_f = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>> +		.bit_idx = 24,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "pwm_f",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_pwm_f_div.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>
>>> [ ... ]
>>>
>>>>> +
>>>>> +/* dmc clk */
>>>>> +static struct clk_regmap a1_dmc_sel = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DMC_CLK_CTRL,
>>>>> +		.mask = 0x3,
>>>>> +		.shift = 9,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dmc_sel",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = sd_emmc_parents,
>>>>> +		.num_parents = 4,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dmc_div = {
>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>> +		.offset = DMC_CLK_CTRL,
>>>>> +		.shift = 0,
>>>>> +		.width = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dmc_div",
>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dmc_sel.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>> +		.offset = DMC_CLK_CTRL,
>>>>> +		.mask = 0x1,
>>>>> +		.shift = 15,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data){
>>>>> +		.name = "dmc_sel2",
>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>> +			{ .hw = &a1_dmc_div.hw },
>>>>> +			{ .fw_name = "xtal", },
>>>>> +		},
>>>>> +		.num_parents = 2,
>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +static struct clk_regmap a1_dmc = {
>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>> +		.offset = DMC_CLK_CTRL,
>>>>> +		.bit_idx = 8,
>>>>> +	},
>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>> +		.name = "dmc",
>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>> +			&a1_dmc_sel2.hw
>>>>> +		},
>>>>> +		.num_parents = 1,
>>>>> +		/*
>>>>> +		 * This clock is used by DDR clock which setted in BL2
>>>>> +		 * and is required by the platform to operate correctly.
>>>>> +		 * Until the following condition are met, we need this clock to
>>>>> +		 * be marked as critical:
>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>> +		 *    clock stays on until the proper driver comes along
>>>>> +		 */
>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>>> +	},
>>>>> +};
>>>>
>>>> Should you put all this DMC stuff in RO until you got a driver for it ?
>>> OK, replace as clk_regmap_gate_ro_ops
>>>>
>>> [ ... ]
>>>>> +
>>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>>> +{
>>>>> +	int ret;
>>>>> +
>>>>> +	ret = meson_eeclkc_probe(pdev);
>>>>> +	if (ret)
>>>>> +		return ret;
>>>>> +
>>>>> +	return 0;
>>>>> +}
>>>>
>>>> Again this function is function is useless and it makes me wonder if you
>>>> should really be using meson_eeclkc_probe()
>>>>
>>>> This makes you use syscon which is not correct unless you have a good
>>>> reason ?
>>>>
>>> If it can not use the meson_eeclkc_probe(), I will realize a probe function
>>> which is mostly duplicate with meson_eeclkc_probe() except
>>> "syscon_node_to_regmap"
>>>
>>> Maybe another common probe function and a new file are required for A1
>>> three drivers? (include the CPU clock driver)
>>
>> Maybe
>>
> I will add a new function base on meson-eeclk.c
>>>
>>> Or using meson_eeclkc_probe is more easier?
>>
>> It is not question of easiness, but correctness.
>>
>>>
>>>> Is there anything but clocks and resets in these register region ?
>>> No, there is only clocks in the register region.
>>> the same does the PLL register region.
>>
>> Then there is no reason to use syscon for those drivers
>>Add a new probe function for A1
>>>>
>>>>> +
>>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>>> +		.regmap_clks = a1_periphs_regmaps,
>>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>>> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>>> +};
>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>> +	{
>>>>> +		.compatible = "amlogic,a1-periphs-clkc",
>>>>> +		.data = &a1_periphs_data
>>>>> +	},
>>>>> +	{ /* sentinel */ }
>>>>> +};
>>>>> +
>>>>> +static struct platform_driver a1_driver = {
>>>>> +	.probe		= meson_a1_periphs_probe,
>>>>> +	.driver		= {
>>>>> +		.name	= "a1-periphs-clkc",
>>>>> +		.of_match_table = clkc_match_table,
>>>>> +	},
>>>>> +};
>>>>> +
>>>>> +builtin_platform_driver(a1_driver);
>>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>>> new file mode 100644
>>>>> index 0000000..1ae5e04
>>>>> --- /dev/null
>>>>> +++ b/drivers/clk/meson/a1.h
>>>>> @@ -0,0 +1,120 @@
>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>> +/*
>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>> + */
>>>>> +
>>>>> +#ifndef __A1_H
>>>>> +#define __A1_H
>>>>> +
>>>>> +/* peripheral clock controller register offset */
>>>>> +#define SYS_OSCIN_CTRL			0x0
>>>>> +#define RTC_BY_OSCIN_CTRL0		0x4
>>>>> +#define RTC_BY_OSCIN_CTRL1		0x8
>>>>> +#define RTC_CTRL			0xc
>>>>> +#define SYS_CLK_CTRL0			0x10
>>>>> +#define AXI_CLK_CTRL0			0x14
>>>>> +#define SYS_CLK_EN0			0x1c
>>>>> +#define SYS_CLK_EN1			0x20
>>>>> +#define AXI_CLK_EN			0x24
>>>>> +#define DSPA_CLK_EN			0x28
>>>>> +#define DSPB_CLK_EN			0x2c
>>>>> +#define DSPA_CLK_CTRL0			0x30
>>>>> +#define DSPB_CLK_CTRL0			0x34
>>>>> +#define CLK12_24_CTRL			0x38
>>>>> +#define GEN_CLK_CTRL			0x3c
>>>>> +#define TIMESTAMP_CTRL0			0x40
>>>>> +#define TIMESTAMP_CTRL1			0x44
>>>>> +#define TIMESTAMP_CTRL2			0x48
>>>>> +#define TIMESTAMP_VAL0			0x4c
>>>>> +#define TIMESTAMP_VAL1			0x50
>>>>> +#define TIMEBASE_CTRL0			0x54
>>>>> +#define TIMEBASE_CTRL1			0x58
>>>>> +#define SAR_ADC_CLK_CTRL		0xc0
>>>>> +#define PWM_CLK_AB_CTRL			0xc4
>>>>> +#define PWM_CLK_CD_CTRL			0xc8
>>>>> +#define PWM_CLK_EF_CTRL			0xcc
>>>>> +#define SPICC_CLK_CTRL			0xd0
>>>>> +#define TS_CLK_CTRL			0xd4
>>>>> +#define SPIFC_CLK_CTRL			0xd8
>>>>> +#define USB_BUSCLK_CTRL			0xdc
>>>>> +#define SD_EMMC_CLK_CTRL		0xe0
>>>>> +#define CECA_CLK_CTRL0			0xe4
>>>>> +#define CECA_CLK_CTRL1			0xe8
>>>>> +#define CECB_CLK_CTRL0			0xec
>>>>> +#define CECB_CLK_CTRL1			0xf0
>>>>> +#define PSRAM_CLK_CTRL			0xf4
>>>>> +#define DMC_CLK_CTRL			0xf8
>>>>> +#define FCLK_DIV1_SEL			0xfc
>>>>> +#define TST_CTRL			0x100
>>>>> +
>>>>> +#define CLKID_XTAL_CLKTREE		0
>>>>> +#define CLKID_SYS_A_SEL			89
>>>>> +#define CLKID_SYS_A_DIV			90
>>>>> +#define CLKID_SYS_A			91
>>>>> +#define CLKID_SYS_B_SEL			92
>>>>> +#define CLKID_SYS_B_DIV			93
>>>>> +#define CLKID_SYS_B			94
>>>>> +#define CLKID_DSPA_A_SEL		95
>>>>> +#define CLKID_DSPA_A_DIV		96
>>>>> +#define CLKID_DSPA_A			97
>>>>> +#define CLKID_DSPA_B_SEL		98
>>>>> +#define CLKID_DSPA_B_DIV		99
>>>>> +#define CLKID_DSPA_B			100
>>>>> +#define CLKID_DSPB_A_SEL		101
>>>>> +#define CLKID_DSPB_A_DIV		102
>>>>> +#define CLKID_DSPB_A			103
>>>>> +#define CLKID_DSPB_B_SEL		104
>>>>> +#define CLKID_DSPB_B_DIV		105
>>>>> +#define CLKID_DSPB_B			106
>>>>> +#define CLKID_RTC_32K_CLKIN		107
>>>>> +#define CLKID_RTC_32K_DIV		108
>>>>> +#define CLKID_RTC_32K_XTAL		109
>>>>> +#define CLKID_RTC_32K_SEL		110
>>>>> +#define CLKID_CECB_32K_CLKIN		111
>>>>> +#define CLKID_CECB_32K_DIV		112
>>>>> +#define CLKID_CECB_32K_SEL_PRE		113
>>>>> +#define CLKID_CECB_32K_SEL		114
>>>>> +#define CLKID_CECA_32K_CLKIN		115
>>>>> +#define CLKID_CECA_32K_DIV		116
>>>>> +#define CLKID_CECA_32K_SEL_PRE		117
>>>>> +#define CLKID_CECA_32K_SEL		118
>>>>> +#define CLKID_DIV2_PRE			119
>>>>> +#define CLKID_24M_DIV2			120
>>>>> +#define CLKID_GEN_SEL			121
>>>>> +#define CLKID_GEN_DIV			122
>>>>> +#define CLKID_SARADC_DIV		123
>>>>> +#define CLKID_PWM_A_SEL			124
>>>>> +#define CLKID_PWM_A_DIV			125
>>>>> +#define CLKID_PWM_B_SEL			126
>>>>> +#define CLKID_PWM_B_DIV			127
>>>>> +#define CLKID_PWM_C_SEL			128
>>>>> +#define CLKID_PWM_C_DIV			129
>>>>> +#define CLKID_PWM_D_SEL			130
>>>>> +#define CLKID_PWM_D_DIV			131
>>>>> +#define CLKID_PWM_E_SEL			132
>>>>> +#define CLKID_PWM_E_DIV			133
>>>>> +#define CLKID_PWM_F_SEL			134
>>>>> +#define CLKID_PWM_F_DIV			135
>>>>> +#define CLKID_SPICC_SEL			136
>>>>> +#define CLKID_SPICC_DIV			137
>>>>> +#define CLKID_SPICC_SEL2		138
>>>>> +#define CLKID_TS_DIV			139
>>>>> +#define CLKID_SPIFC_SEL			140
>>>>> +#define CLKID_SPIFC_DIV			141
>>>>> +#define CLKID_SPIFC_SEL2		142
>>>>> +#define CLKID_USB_BUS_SEL		143
>>>>> +#define CLKID_USB_BUS_DIV		144
>>>>> +#define CLKID_SD_EMMC_SEL		145
>>>>> +#define CLKID_SD_EMMC_DIV		146
>>>>> +#define CLKID_SD_EMMC_SEL2		147
>>>>> +#define CLKID_PSRAM_SEL			148
>>>>> +#define CLKID_PSRAM_DIV			149
>>>>> +#define CLKID_PSRAM_SEL2		150
>>>>> +#define CLKID_DMC_SEL			151
>>>>> +#define CLKID_DMC_DIV			152
>>>>> +#define CLKID_DMC_SEL2			153
>>>>> +#define NR_CLKS				154
>>>>> +
>>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>>> +
>>>>> +#endif /* __A1_H */
>>>>
>>>> .
>>>>
>>
>> .
>>


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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-12 16:59           ` Jerome Brunet
@ 2019-11-13 14:21             ` Jian Hu
  2019-11-20  9:28               ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-13 14:21 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On 2019/11/13 0:59, Jerome Brunet wrote:
> 
> On Sat 09 Nov 2019 at 12:16, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Jerome
>>
>> Sorry for late rely
>>
>> On 2019/11/4 16:24, Jerome Brunet wrote:
>>>
>>> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> Hi, Jerome
>>>>
>>>> Thanks for your review
>>>>
>>>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>>>
>>>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>
>>>>>> The Amlogic A1 clock includes three drivers:
>>>>>> peripheral clocks, pll clocks, CPU clocks.
>>>>>> sys pll and CPU clocks will be sent in next patch.
>>>>>>
>>>>>> Unlike the previous series, there is no EE/AO domain
>>>>>> in A1 CLK controllers.
>>>>>>
>>>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>>>> ---
>>>>>>     drivers/clk/meson/Kconfig  |   10 +
>>>>>>     drivers/clk/meson/Makefile |    1 +
>>>>>>     drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>>>     drivers/clk/meson/a1-pll.h |   56 ++
>>>>>>     drivers/clk/meson/a1.c     | 2264 ++++++++++++++++++++++++++++++++++++++++++++
>>>>>>     drivers/clk/meson/a1.h     |  120 +++
>>>>>>     6 files changed, 2796 insertions(+)
>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.c
>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.h
>>>>>>     create mode 100644 drivers/clk/meson/a1.c
>>>>>>     create mode 100644 drivers/clk/meson/a1.h
>>>>>
>>>>> In the next version, one
>>>> OK, I will send a1 peripheral and pll driver in two patch.
>>>>>
>>>>>>
>>>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>>>> index dabeb43..c2809b2 100644
>>>>>> --- a/drivers/clk/meson/Kconfig
>>>>>> +++ b/drivers/clk/meson/Kconfig
>>>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>>>     	  Support for the audio clock controller on AmLogic A113D devices,
>>>>>>     	  aka axg, Say Y if you want audio subsystem to work.
>>>>>>     +config COMMON_CLK_A1
>>>>>> +	bool
>>>>>> +	depends on ARCH_MESON
>>>>>> +	select COMMON_CLK_MESON_REGMAP
>>>>>> +	select COMMON_CLK_MESON_DUALDIV
>>>>>> +	select COMMON_CLK_MESON_PLL
>>>>>> +	help
>>>>>> +	  Support for the clock controller on Amlogic A113L device,
>>>>>> +	  aka a1. Say Y if you want peripherals to work.
>>>>>> +
>>>>>>     config COMMON_CLK_G12A
>>>>>>     	bool
>>>>>>     	depends on ARCH_MESON
>>>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>>>> index 3939f21..28cbae1 100644
>>>>>> --- a/drivers/clk/meson/Makefile
>>>>>> +++ b/drivers/clk/meson/Makefile
>>>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
>>>>>>       obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>>>     obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>>>
>>>>> So far, all the controller had there own option, I don't see why it
>>>>> should be different here.
>>>>>
>>>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll driver
>>>>>>     obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>>>     obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>>>     obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>>>> new file mode 100644
>>>>>> index 0000000..486d964
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>>>> @@ -0,0 +1,345 @@
>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>> +/*
>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/platform_device.h>
>>>>>
>>>>> Hum ... looks like some things are missing here
>>>>>
>>>>> #include <linux/of_device.h>
>>>>> #include <linux/clk-provider.h>
>>>>>
>>>>> ?
>>>> #1
>>>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>>>
>>>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>>>
>>>> #2
>>>> For A1 driver, the file "linux/of_device.h" is not required.
>>>> It is required by meson-eeclk.c in fact.
>>>
>>> You are using what is provided by these headers directly in this file
>>> If meson-eeclk ever changes, your driver breaks
>>>
>> OK, I will add the two header file.
>>>>>
>>>>>> +#include "clk-pll.h"
>>>>>> +#include "meson-eeclk.h"
>>>>>> +#include "a1-pll.h"
>>>>>
>>>>> Alphanumeric order please
>>>>>
>>>> OK, I will change it in the next version.
>>>>
>>>>>> +
>>>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>>>> +	.data = &(struct meson_clk_pll_data){
>>>>>> +		.en = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>> +			.shift   = 28,
>>>>>> +			.width   = 1,
>>>>>> +		},
>>>>>> +		.m = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>> +			.shift   = 0,
>>>>>> +			.width   = 8,
>>>>>> +		},
>>>>>> +		.n = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>> +			.shift   = 10,
>>>>>> +			.width   = 5,
>>>>>> +		},
>>>>>> +		.frac = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL1,
>>>>>> +			.shift   = 0,
>>>>>> +			.width   = 19,
>>>>>> +		},
>>>>>> +		.l = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>> +			.shift   = 31,
>>>>>> +			.width   = 1,
>>>>>> +		},
>>>>>> +		.rst = {
>>>>>> +			.reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>> +			.shift   = 29,
>>>>>> +			.width   = 1,
>>>>>> +		},
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fixed_pll_dco",
>>>>>> +		.ops = &meson_clk_pll_ro_ops,
>>>>>> +		.parent_data = &(const struct clk_parent_data){
>>>>>> +			.fw_name = "xtal_fixpll",
>>>>>> +			.name = "xtal_fixpll",
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_fixed_pll = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>>> +		.bit_idx = 20,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "fixed_pll",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fixed_pll_dco.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * This clock is fclk_div2/3/4's parent,
>>>>>> +		 * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>>>
>>>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>>>
>>>>>> +		 * It is required by the platform to operate correctly.
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>
>>>>> Don't blindly copy/paste comments from other drivers. There is no driver
>>>>> for the devices you are mentionning so the end of the comment is
>>>>> confusing. The 3 first lines were enough
>>>>>
>>>> OK, I will remove the confusing comments
>>>>
>>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>>
>>>>> >From your comment, I understand that some child are critical, not this
>>>>> particular (or at least, not directly). So this can be removed AFAICT
>>>>>
>>>>> You should even need CLK_IGNORE_UNUSED for this one since the clock will
>>>>> already be enabled before the late_init() kicks in
>>>>>
>>>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>>>> +	.min = 32,
>>>>>> +	.max = 64,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = 10 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = 40 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_hifi_pll = {
>>>>>> +	.data = &(struct meson_clk_pll_data){
>>>>>> +		.en = {
>>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>> +			.shift   = 28,
>>>>>> +			.width   = 1,
>>>>>> +		},
>>>>>> +		.m = {
>>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>> +			.shift   = 0,
>>>>>> +			.width   = 8,
>>>>>> +		},
>>>>>> +		.n = {
>>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>> +			.shift   = 10,
>>>>>> +			.width   = 5,
>>>>>> +		},
>>>>>> +		.frac = {
>>>>>> +			.reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>>>> +			.shift   = 0,
>>>>>> +			.width   = 19,
>>>>>> +		},
>>>>>> +		.l = {
>>>>>> +			.reg_off = ANACTRL_HIFIPLL_STS,
>>>>>> +			.shift   = 31,
>>>>>> +			.width   = 1,
>>>>>> +		},
>>>>>> +		.range = &a1_hifi_pll_mult_range,
>>>>>> +		.init_regs = a1_hifi_init_regs,
>>>>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>> +		.strict_sequence = true,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "hifi_pll",
>>>>>> +		.ops = &meson_clk_pll_ops,
>>>>>> +		.parent_data = &(const struct clk_parent_data){
>>>>>> +			.fw_name = "xtal_fixpll",
>>>>>> +			.name = "xtal_fixpll",
>>>>>
>>>>> Both should provided when a controller transition from the old way of
>>>>> describing parent to the new way. This is a new controller so it does
>>>>> not apply.
>>>> I do not understand why it does not apply, could you explain more?
>>>
>>> Your driver is new, it is not something old transitioning from global
>>> name to clock in DT !
>>>
>>>>
>>>> The xtal_fixpll clock is registered in another peripheral driver, If do not
>>>> desribe the "name" member in parent_data, "fw_name" does not work because
>>>> it has not been registered. the hifi_pll parent will be null in
>>>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>>>
>>>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
>>>
>>> There will be an orphan yes, temporarily, until both controllers are up.
>>> Once both controller are up, the clock will be reparented if necessary.
>>>
>>>>
>>>> So both of "fw_name" of "name" should be described.
>>>
>>> No
>>>
>>
>> #1
>>
>> Here, I am still confused.
>>  From the point of view of the phenomenon, the name in parent_data is
>> required.
>>
>>
>> HIFI PLL is described like this:
>>
>> 	.parent_data = &(const struct clk_parent_data){
>> 		.fw_name = "xtal_hifipll",
>> 		.name = "xtal_hifipll"
>> 	}
>>
>> Fixed PLL is described like this:
>>
>> 	.parent_data = &(const struct clk_parent_data){
>> 		.fw_name = "xtal_fixpll",
>> 	},
>>
>> After the system boot completely, run cat
>> /sys/kernel/debug/clk/clk_summary, Here is the result:
>>
>> # cat /sys/kernel/debug/clk/clk_summary
>>                   enable  prepare  protect                    duty
>>     clock         count   count    count  rate accuracy phase cycle
>> --------------------------------------------------------------------
>>   xtal            5        5        0    24000000    0     0  50000
>>      ts_div       0        0        0    24000000    0     0  50000
>>         ts        0        0        0    24000000    0     0  50000
>>      pwm_f_sel    0        0        0    24000000    0     0  50000
>>         pwm_f_div 0        0        0    24000000    0     0  50000
>>            pwm_f  0        0        0    24000000    0     0  50000
>> ......
>>      xtal_syspll  0        0        0    24000000    0     0  50000
>>      xtal_hifipll 0        0        0    24000000    0     0  50000
>>         hifi_pll  0        0        0  1536000000    0     0  50000
>>      xtal_usb_ctrl 0        0        0    24000000   0     0  50000
>>      xtal_usb_phy  0        0        0    24000000   0     0  50000
>>      xtal_fixpll   0        0        0    24000000   0     0  50000
>>      xtal_clktree  0        0        0    24000000   0     0  50000
>>   fixed_pll_dco    1        1        0         0   0     0  50000
> 
> This means that CCF what not able to resolve the parent.
> Either:
> * you've made a mistake somewhere
> * There is bug in CCF when the parent device is not available at probe
> time, the clock is not properly reparented
> 

#1 Add DT describtion

DT description:

clkc_pll: pll-clock-controller {
       compatible = "amlogic,a1-pll-clkc";
       #clock-cells = <1>;
       reg = <0 0x7c80 0 0x21c>;
       clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
             <&clkc_periphs CLKID_XTAL_HIFIPLL>;
       clock-names = "xtal_fixpll", "xtal_hifipll";
};

clkc_periphs: periphs-clock-controller {
       compatible = "amlogic,a1-periphs-clkc";
       #clock-cells = <1>;
       reg = <0 0x800 0 0x104>;
       clocks = <&clkc_pll CLKID_FCLK_DIV2>,
                <&clkc_pll CLKID_FCLK_DIV3>,
                <&clkc_pll CLKID_FCLK_DIV5>,
                <&clkc_pll CLKID_FCLK_DIV7>,
                <&clkc_pll CLKID_HIFI_PLL>,
                <&xtal>;
       clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
                     "fclk_div7", "hifi_pll", "xtal";
};

And PLL clock driver probe first.

When register xtal_fixpll clock in periphs driver

it will walk the list of orphan clocks, it will try to get the orphan 
parent.

the code path is :

struct clk_core *parent = __clk_init_parent(orphan)

   -> clk_core_get_parent_by_index(core, index)

    ->clk_core_fill_parent_index

     ->clk_core_get

      ->of_clk_get_hw_from_clkspec

In of_clk_get_hw_from_clkspec function, it will get hw_clk from 
clk_provider, However the peripheral clock provider has not been
added to "of_clk_providers" LIST, In other words, the peripheral clock
provider does not exist at this time. (devm_of_clk_add_hw_provider has 
not run)

So It will get parent failed from DT.

even if name is added in parent_data, PTR_ERR(parent) is not equal 
-ENOENT, it will not run clk_core_lookup, the fixed_pll_dco is still a 
orphan clock.

#2 Not add DT describtion

the code path is :

struct clk_core *parent = __clk_init_parent(orphan)

   -> clk_core_get_parent_by_index(core, index)

    ->clk_core_fill_parent_index

     ->clk_core_get

      ->clk_find_hw

clk_find_hw is used when the clock is registered by clk_register_clkdev

So it wlll get parented failed by clk_find_hw.

When name is described in parent_data, the parent will be found by

clk_core_lookup.


In this scene,Only fw_name in parent_data, the orphan clock's parent can 
not be found, But add the legacy name, the parent will be found.

#3
When the provider has not been added to the CCF, And fw_name is alone in 
parent_data in a orphan clock , How to get the orphan clock'parent ?
It seems not supported.

> Either way, you'll have to debug a bit more
> 
>>      fixed_pll     3        3        0         0   0     0  50000
>>         fclk_div7_div 0     0        0         0   0     0  50000
>> ....
>>
>> the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is right.
>>
>> but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
>> is zero.When the name in parent_data is added, its parent is xtal_fixpll.
>>
>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
>> #
>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
>> 0
>>
>>
>> #2
>> In  ./drivers/clk/qcom/gcc-sm8150.c
>> For some clocks, Both fw_name and name are described in parent_data
>> struct.
> 
> Those are being migrated to DT description which means that we don't
> know if the DT will the correct description
> 
> In this case the clock framework will first try DT and if DT does
> provide this fw_name, it will fallback to the legacy name.
> 
> This is not your case as this is a new platform for which we know the DT
> name exist.
> 
It will get parent failed from DT as the previous says.
>>
>>>>
>>>>>
>>>>> Same for the other occurences.
>>>>>
>>>>> Also, I think you meant xtal_hifipll
>>>> Yes,I will correct it.
>>>>>
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>>>> +	.mult = 1,
>>>>>> +	.div = 2,
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div2_div",
>>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fixed_pll.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>>> +		.bit_idx = 21,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div2",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fclk_div2_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * This clock is used by DDR clock in BL2 firmware
>>>>>> +		 * and is required by the platform to operate correctly.
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>>>> +	.mult = 1,
>>>>>> +	.div = 3,
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div3_div",
>>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fixed_pll.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>>> +		.bit_idx = 22,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div3",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fclk_div3_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * This clock is used by APB bus which setted in Romcode
>>>>>> +		 * and is required by the platform to operate correctly.
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>>>> +	.mult = 1,
>>>>>> +	.div = 5,
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div5_div",
>>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fixed_pll.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>>> +		.bit_idx = 23,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div5",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fclk_div5_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * This clock is used by AXI bus which setted in Romcode
>>>>>> +		 * and is required by the platform to operate correctly.
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>>>> +	.mult = 1,
>>>>>> +	.div = 7,
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div7_div",
>>>>>> +		.ops = &clk_fixed_factor_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fixed_pll.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = ANACTRL_FIXPLL_CTRL0,
>>>>>> +		.bit_idx = 24,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "fclk_div7",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_fclk_div7_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* Array of all clocks provided by this provider */
>>>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>>>> +	.hws = {
>>>>>> +		[CLKID_FIXED_PLL_DCO]		= &a1_fixed_pll_dco.hw,
>>>>>> +		[CLKID_FIXED_PLL]		= &a1_fixed_pll.hw,
>>>>>> +		[CLKID_HIFI_PLL]		= &a1_hifi_pll.hw,
>>>>>> +		[CLKID_FCLK_DIV2]		= &a1_fclk_div2.hw,
>>>>>> +		[CLKID_FCLK_DIV3]		= &a1_fclk_div3.hw,
>>>>>> +		[CLKID_FCLK_DIV5]		= &a1_fclk_div5.hw,
>>>>>> +		[CLKID_FCLK_DIV7]		= &a1_fclk_div7.hw,
>>>>>> +		[CLKID_FCLK_DIV2_DIV]		= &a1_fclk_div2_div.hw,
>>>>>> +		[CLKID_FCLK_DIV3_DIV]		= &a1_fclk_div3_div.hw,
>>>>>> +		[CLKID_FCLK_DIV5_DIV]		= &a1_fclk_div5_div.hw,
>>>>>> +		[CLKID_FCLK_DIV7_DIV]		= &a1_fclk_div7_div.hw,
>>>>>> +		[NR_PLL_CLKS]			= NULL,
>>>>>> +	},
>>>>>> +	.num = NR_PLL_CLKS,
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>>>> +	&a1_fixed_pll_dco,
>>>>>> +	&a1_fixed_pll,
>>>>>> +	&a1_hifi_pll,
>>>>>> +	&a1_fclk_div2,
>>>>>> +	&a1_fclk_div3,
>>>>>> +	&a1_fclk_div5,
>>>>>> +	&a1_fclk_div7,
>>>>>> +};
>>>>>> +
>>>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	ret = meson_eeclkc_probe(pdev);
>>>>>> +	if (ret)
>>>>>> +		return ret;
>>>>>> +
>>>>>> +	return 0;
>>>>>> +}
>>>>>
>>>>> This function is useless.
>>>>>
>>>> OK, I will use meson_eeclkc_probe derectly.
>>>>>> +
>>>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>>>> +		.regmap_clks = a1_pll_regmaps,
>>>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>>>> +		.hw_onecell_data = &a1_pll_hw_onecell_data,
>>>>>> +};
>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>> +	{
>>>>>> +		.compatible = "amlogic,a1-pll-clkc",
>>>>>> +		.data = &a1_pll_data
>>>>>> +	},
>>>>>> +	{ /* sentinel */ }
>>>>>
>>>>> Nitpick: don't need to write this, just write the line like this
>>>>>
>>>> OK, remove it.
>>>>> ' }, {}'
>>>>>
>>>>>> +};
>>>>>> +
>>>>>> +static struct platform_driver a1_driver = {
>>>>>> +	.probe		= meson_a1_pll_probe,
>>>>>> +	.driver		= {
>>>>>> +		.name	= "a1-pll-clkc",
>>>>>> +		.of_match_table = clkc_match_table,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +builtin_platform_driver(a1_driver);
>>>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>>>> new file mode 100644
>>>>>> index 0000000..99ee2a9
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>>>> @@ -0,0 +1,56 @@
>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>> +/*
>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef __A1_PLL_H
>>>>>> +#define __A1_PLL_H
>>>>>> +
>>>>>> +/* PLL register offset */
>>>>>> +#define ANACTRL_FIXPLL_CTRL0		0x80
>>>>>> +#define ANACTRL_FIXPLL_CTRL1		0x84
>>>>>> +#define ANACTRL_FIXPLL_CTRL2		0x88
>>>>>> +#define ANACTRL_FIXPLL_CTRL3		0x8c
>>>>>> +#define ANACTRL_FIXPLL_CTRL4		0x90
>>>>>> +#define ANACTRL_FIXPLL_STS		0x94
>>>>>> +#define ANACTRL_SYSPLL_CTRL0		0x100
>>>>>> +#define ANACTRL_SYSPLL_CTRL1		0x104
>>>>>> +#define ANACTRL_SYSPLL_CTRL2		0x108
>>>>>> +#define ANACTRL_SYSPLL_CTRL3		0x10c
>>>>>> +#define ANACTRL_SYSPLL_CTRL4		0x110
>>>>>> +#define ANACTRL_SYSPLL_STS		0x114
>>>>>> +#define ANACTRL_HIFIPLL_CTRL0		0x140
>>>>>> +#define ANACTRL_HIFIPLL_CTRL1		0x144
>>>>>> +#define ANACTRL_HIFIPLL_CTRL2		0x148
>>>>>> +#define ANACTRL_HIFIPLL_CTRL3		0x14c
>>>>>> +#define ANACTRL_HIFIPLL_CTRL4		0x150
>>>>>> +#define ANACTRL_HIFIPLL_STS		0x154
>>>>>> +#define ANACTRL_AUDDDS_CTRL0		0x180
>>>>>> +#define ANACTRL_AUDDDS_CTRL1		0x184
>>>>>> +#define ANACTRL_AUDDDS_CTRL2		0x188
>>>>>> +#define ANACTRL_AUDDDS_CTRL3		0x18c
>>>>>> +#define ANACTRL_AUDDDS_CTRL4		0x190
>>>>>> +#define ANACTRL_AUDDDS_STS		0x194
>>>>>> +#define ANACTRL_MISCTOP_CTRL0		0x1c0
>>>>>> +#define ANACTRL_POR_CNTL		0x208
>>>>>> +
>>>>>> +/*
>>>>>> + * CLKID index values
>>>>>> + *
>>>>>> + * These indices are entirely contrived and do not map onto the hardware.
>>>>>> + * It has now been decided to expose everything by default in the DT header:
>>>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
>>>>>> + * to expose, such as the internal muxes and dividers of composite clocks,
>>>>>> + * will remain defined here.
>>>>>> + */
>>>>>> +#define CLKID_FIXED_PLL_DCO		0
>>>>>> +#define CLKID_FCLK_DIV2_DIV		2
>>>>>> +#define CLKID_FCLK_DIV3_DIV		3
>>>>>> +#define CLKID_FCLK_DIV5_DIV		4
>>>>>> +#define CLKID_FCLK_DIV7_DIV		5
>>>>>> +#define NR_PLL_CLKS			11
>>>>>> +
>>>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>>>> +
>>>>>> +#endif /* __A1_PLL_H */
>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>> new file mode 100644
>>>>>> index 0000000..86a4733
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>> @@ -0,0 +1,2264 @@
>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>> +/*
>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/platform_device.h>
>>>>>> +#include "clk-pll.h"
>>>>>> +#include "clk-dualdiv.h"
>>>>>> +#include "meson-eeclk.h"
>>>>>> +#include "a1.h"
>>>>>
>>>>> Same as above
>>>> OK, I will change the order.
>>>> In fact, the clk-pll.h is not used in the current driver.
>>>> I will remove it.
>>>>>
>>>>>> +
>>>>>> +/* PLLs clock in gates, its parent is xtal */
>>>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = SYS_OSCIN_CTRL,
>>>>>> +		.bit_idx = 0,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "xtal_clktree",
>>>>>> +		.ops = &clk_regmap_gate_ro_ops,
>>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>>> +			.fw_name = "xtal",
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * switch for xtal clock
>>>>>> +		 * Linux should not change it at runtime
>>>>>> +		 */
>>>>>
>>>>> Comment not useful: it uses the Ro ops
>>>>>
>>>> OK,  remove the comments
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = SYS_OSCIN_CTRL,
>>>>>> +		.bit_idx = 1,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "xtal_fixpll",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>>> +			.fw_name = "xtal",
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_IS_CRITICAL,
>>>>>> +		/*
>>>>>> +		 * it feeds DDR,AXI,APB bus
>>>>>> +		 * Linux should not change it at runtime
>>>>>> +		 */
>>>>>
>>>>> Again, the child are critical, not directly this clock from your
>>>>> comment.
>>>>>
>>>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>>>
>>>> repace as clk_regmap_gate_ro_ops
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>
>>>> [ ... ]
>>>>
>>>>>> +
>>>>>> +/* dsp a clk */
>>>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>>>> +	{ .fw_name = "xtal", },
>>>>>> +	{ .fw_name = "fclk_div2", },
>>>>>> +	{ .fw_name = "fclk_div3", },
>>>>>> +	{ .fw_name = "fclk_div5", },
>>>>>> +	{ .fw_name = "hifi_pll", },
>>>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.mask = 0x7,
>>>>>> +		.shift = 10,
>>>>>> +		.table = mux_table_dsp_ab,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspa_a_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>
>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>> Yes, I miss the flag.
>>>>>
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 10,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspa_a_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_a_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_a = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.bit_idx = 13,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspa_a",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_a_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.mask = 0x7,
>>>>>> +		.shift = 26,
>>>>>> +		.table = mux_table_dsp_ab,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspa_b_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>
>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>
>>>> Yes, I will add it.
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.shift = 16,
>>>>>> +		.width = 10,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspa_b_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_b_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_b = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.bit_idx = 29,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspa_b",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_b_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPA_CLK_CTRL0,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 15,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspa_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>>> +			{ .hw = &a1_dspa_a.hw },
>>>>>> +			{ .hw = &a1_dspa_b.hw },
>>>>>> +		},
>>>>>> +		.num_parents = 2,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPA_CLK_EN,
>>>>>> +		.bit_idx = 1,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspa_en_dspa",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>
>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>
>>>> I should remove it
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPA_CLK_EN,
>>>>>> +		.bit_idx = 0,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspa_en_nic",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspa_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>
>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>
>>>> I should remove it
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>
>>>>> Same question and remarks applies to DSP B
>>>>>
>>>> got it
>>>>>> +/* dsp b clk */
>>>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.mask = 0x7,
>>>>>> +		.shift = 10,
>>>>>> +		.table = mux_table_dsp_ab,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspb_a_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 10,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspb_a_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_a_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_a = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.bit_idx = 13,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspb_a",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_a_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.mask = 0x7,
>>>>>> +		.shift = 26,
>>>>>> +		.table = mux_table_dsp_ab,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspb_b_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = dsp_ab_clk_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.shift = 16,
>>>>>> +		.width = 10,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspb_b_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_b_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_b = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.bit_idx = 29,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspb_b",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_b_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DSPB_CLK_CTRL0,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 15,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dspb_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_a.hw, &a1_dspb_b.hw,
>>>>>> +		},
>>>>>> +		.num_parents = 2,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPB_CLK_EN,
>>>>>> +		.bit_idx = 1,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspb_en_dspb",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DSPB_CLK_EN,
>>>>>> +		.bit_idx = 0,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dspb_en_nic",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dspb_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* 12M/24M clock */
>>>>>> +static struct clk_regmap a1_24m = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = CLK12_24_CTRL,
>>>>>> +		.bit_idx = 11,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "24m",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>>>> +			.fw_name = "xtal",
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>
>>>> [ ... ]
>>>>
>>>>>> +static struct clk_regmap a1_saradc_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 9,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "saradc_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>>> +			{ .fw_name = "xtal", },
>>>>>> +			{ .hw = &a1_sys_clk.hw, },
>>>>>> +		},
>>>>>> +		.num_parents = 2,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_saradc_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "saradc_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_saradc_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_saradc_clk = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = SAR_ADC_CLK_CTRL,
>>>>>> +		.bit_idx = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "saradc_clk",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_saradc_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm a/b/c/d parent data */
>>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>>> +	{ .fw_name = "xtal", },
>>>>>> +	{ .hw = &a1_sys_clk.hw },
>>>>>> +};
>>>>>
>>>>> Looks like the same as SAR ADC
>>>>>
>>>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>>>> +
>>>>>> +/* pwm a clk */
>>>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 9,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_a_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_a_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_a_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_a = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.bit_idx = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_a",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_a_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * The CPU working voltage is controlled by pwm_a
>>>>>> +		 * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>>>> +		 * to avoid changing at runtime.
>>>>>                                        ^ it
>>>>>
>>>>>> +		 * and is required by the platform to operate correctly.
>>>>>                       "blabla. And" is strange
>>>>>
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>
>>>>> This only skips the late_init() disable of unused clocks
>>>>>
>>>>> Be aware that this is not fool-proof. If at any time a driver enable
>>>>> then disable the clock, the clock will be disable and I guess your
>>>>> platform will die if this provides the CPU voltage.
>>>> OK, CLK_IS_CRITICAL is better.
>>>>>
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm b clk */
>>>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 25,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_b_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.shift = 16,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_b_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_b_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_b = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_AB_CTRL,
>>>>>> +		.bit_idx = 24,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_b",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_b_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm c clk */
>>>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 9,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_c_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_c_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_c_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_c = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.bit_idx = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_c",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_c_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm d clk */
>>>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 25,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_d_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.shift = 16,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_d_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_d_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_d = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_CD_CTRL,
>>>>>> +		.bit_idx = 24,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_d",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_d_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>>>> +	{ .fw_name = "xtal", },
>>>>>> +	{ .hw = &a1_sys_clk.hw },
>>>>>> +	{ .fw_name = "fclk_div5", },
>>>>>> +	{ .hw = &a1_rtc_clk.hw },
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm e clk */
>>>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.mask = 0x3,
>>>>>> +		.shift = 9,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_e_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_ef_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_e_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_e_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_e = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.bit_idx = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_e",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_e_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +/* pwm f clk */
>>>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.mask = 0x3,
>>>>>> +		.shift = 25,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_f_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = pwm_ef_parent_data,
>>>>>> +		.num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.shift = 16,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "pwm_f_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_f_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_pwm_f = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = PWM_CLK_EF_CTRL,
>>>>>> +		.bit_idx = 24,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "pwm_f",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_pwm_f_div.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>
>>>> [ ... ]
>>>>
>>>>>> +
>>>>>> +/* dmc clk */
>>>>>> +static struct clk_regmap a1_dmc_sel = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DMC_CLK_CTRL,
>>>>>> +		.mask = 0x3,
>>>>>> +		.shift = 9,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dmc_sel",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = sd_emmc_parents,
>>>>>> +		.num_parents = 4,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dmc_div = {
>>>>>> +	.data = &(struct clk_regmap_div_data){
>>>>>> +		.offset = DMC_CLK_CTRL,
>>>>>> +		.shift = 0,
>>>>>> +		.width = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dmc_div",
>>>>>> +		.ops = &clk_regmap_divider_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dmc_sel.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>>>> +	.data = &(struct clk_regmap_mux_data){
>>>>>> +		.offset = DMC_CLK_CTRL,
>>>>>> +		.mask = 0x1,
>>>>>> +		.shift = 15,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data){
>>>>>> +		.name = "dmc_sel2",
>>>>>> +		.ops = &clk_regmap_mux_ops,
>>>>>> +		.parent_data = (const struct clk_parent_data []) {
>>>>>> +			{ .hw = &a1_dmc_div.hw },
>>>>>> +			{ .fw_name = "xtal", },
>>>>>> +		},
>>>>>> +		.num_parents = 2,
>>>>>> +		.flags = CLK_SET_RATE_PARENT,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +static struct clk_regmap a1_dmc = {
>>>>>> +	.data = &(struct clk_regmap_gate_data){
>>>>>> +		.offset = DMC_CLK_CTRL,
>>>>>> +		.bit_idx = 8,
>>>>>> +	},
>>>>>> +	.hw.init = &(struct clk_init_data) {
>>>>>> +		.name = "dmc",
>>>>>> +		.ops = &clk_regmap_gate_ops,
>>>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>>>> +			&a1_dmc_sel2.hw
>>>>>> +		},
>>>>>> +		.num_parents = 1,
>>>>>> +		/*
>>>>>> +		 * This clock is used by DDR clock which setted in BL2
>>>>>> +		 * and is required by the platform to operate correctly.
>>>>>> +		 * Until the following condition are met, we need this clock to
>>>>>> +		 * be marked as critical:
>>>>>> +		 * a) Mark the clock used by a firmware resource, if possible
>>>>>> +		 * b) CCF has a clock hand-off mechanism to make the sure the
>>>>>> +		 *    clock stays on until the proper driver comes along
>>>>>> +		 */
>>>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>>>> +	},
>>>>>> +};
>>>>>
>>>>> Should you put all this DMC stuff in RO until you got a driver for it ?
>>>> OK, replace as clk_regmap_gate_ro_ops
>>>>>
>>>> [ ... ]
>>>>>> +
>>>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	ret = meson_eeclkc_probe(pdev);
>>>>>> +	if (ret)
>>>>>> +		return ret;
>>>>>> +
>>>>>> +	return 0;
>>>>>> +}
>>>>>
>>>>> Again this function is function is useless and it makes me wonder if you
>>>>> should really be using meson_eeclkc_probe()
>>>>>
>>>>> This makes you use syscon which is not correct unless you have a good
>>>>> reason ?
>>>>>
>>>> If it can not use the meson_eeclkc_probe(), I will realize a probe function
>>>> which is mostly duplicate with meson_eeclkc_probe() except
>>>> "syscon_node_to_regmap"
>>>>
>>>> Maybe another common probe function and a new file are required for A1
>>>> three drivers? (include the CPU clock driver)
>>>
>>> Maybe
>>>
>> I will add a new function base on meson-eeclk.c
>>>>
>>>> Or using meson_eeclkc_probe is more easier?
>>>
>>> It is not question of easiness, but correctness.
>>>
>>>>
>>>>> Is there anything but clocks and resets in these register region ?
>>>> No, there is only clocks in the register region.
>>>> the same does the PLL register region.
>>>
>>> Then there is no reason to use syscon for those drivers
>>> Add a new probe function for A1
>>>>>
>>>>>> +
>>>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>>>> +		.regmap_clks = a1_periphs_regmaps,
>>>>>> +		.regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>>>> +		.hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>>>> +};
>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>> +	{
>>>>>> +		.compatible = "amlogic,a1-periphs-clkc",
>>>>>> +		.data = &a1_periphs_data
>>>>>> +	},
>>>>>> +	{ /* sentinel */ }
>>>>>> +};
>>>>>> +
>>>>>> +static struct platform_driver a1_driver = {
>>>>>> +	.probe		= meson_a1_periphs_probe,
>>>>>> +	.driver		= {
>>>>>> +		.name	= "a1-periphs-clkc",
>>>>>> +		.of_match_table = clkc_match_table,
>>>>>> +	},
>>>>>> +};
>>>>>> +
>>>>>> +builtin_platform_driver(a1_driver);
>>>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>>>> new file mode 100644
>>>>>> index 0000000..1ae5e04
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/meson/a1.h
>>>>>> @@ -0,0 +1,120 @@
>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>> +/*
>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef __A1_H
>>>>>> +#define __A1_H
>>>>>> +
>>>>>> +/* peripheral clock controller register offset */
>>>>>> +#define SYS_OSCIN_CTRL			0x0
>>>>>> +#define RTC_BY_OSCIN_CTRL0		0x4
>>>>>> +#define RTC_BY_OSCIN_CTRL1		0x8
>>>>>> +#define RTC_CTRL			0xc
>>>>>> +#define SYS_CLK_CTRL0			0x10
>>>>>> +#define AXI_CLK_CTRL0			0x14
>>>>>> +#define SYS_CLK_EN0			0x1c
>>>>>> +#define SYS_CLK_EN1			0x20
>>>>>> +#define AXI_CLK_EN			0x24
>>>>>> +#define DSPA_CLK_EN			0x28
>>>>>> +#define DSPB_CLK_EN			0x2c
>>>>>> +#define DSPA_CLK_CTRL0			0x30
>>>>>> +#define DSPB_CLK_CTRL0			0x34
>>>>>> +#define CLK12_24_CTRL			0x38
>>>>>> +#define GEN_CLK_CTRL			0x3c
>>>>>> +#define TIMESTAMP_CTRL0			0x40
>>>>>> +#define TIMESTAMP_CTRL1			0x44
>>>>>> +#define TIMESTAMP_CTRL2			0x48
>>>>>> +#define TIMESTAMP_VAL0			0x4c
>>>>>> +#define TIMESTAMP_VAL1			0x50
>>>>>> +#define TIMEBASE_CTRL0			0x54
>>>>>> +#define TIMEBASE_CTRL1			0x58
>>>>>> +#define SAR_ADC_CLK_CTRL		0xc0
>>>>>> +#define PWM_CLK_AB_CTRL			0xc4
>>>>>> +#define PWM_CLK_CD_CTRL			0xc8
>>>>>> +#define PWM_CLK_EF_CTRL			0xcc
>>>>>> +#define SPICC_CLK_CTRL			0xd0
>>>>>> +#define TS_CLK_CTRL			0xd4
>>>>>> +#define SPIFC_CLK_CTRL			0xd8
>>>>>> +#define USB_BUSCLK_CTRL			0xdc
>>>>>> +#define SD_EMMC_CLK_CTRL		0xe0
>>>>>> +#define CECA_CLK_CTRL0			0xe4
>>>>>> +#define CECA_CLK_CTRL1			0xe8
>>>>>> +#define CECB_CLK_CTRL0			0xec
>>>>>> +#define CECB_CLK_CTRL1			0xf0
>>>>>> +#define PSRAM_CLK_CTRL			0xf4
>>>>>> +#define DMC_CLK_CTRL			0xf8
>>>>>> +#define FCLK_DIV1_SEL			0xfc
>>>>>> +#define TST_CTRL			0x100
>>>>>> +
>>>>>> +#define CLKID_XTAL_CLKTREE		0
>>>>>> +#define CLKID_SYS_A_SEL			89
>>>>>> +#define CLKID_SYS_A_DIV			90
>>>>>> +#define CLKID_SYS_A			91
>>>>>> +#define CLKID_SYS_B_SEL			92
>>>>>> +#define CLKID_SYS_B_DIV			93
>>>>>> +#define CLKID_SYS_B			94
>>>>>> +#define CLKID_DSPA_A_SEL		95
>>>>>> +#define CLKID_DSPA_A_DIV		96
>>>>>> +#define CLKID_DSPA_A			97
>>>>>> +#define CLKID_DSPA_B_SEL		98
>>>>>> +#define CLKID_DSPA_B_DIV		99
>>>>>> +#define CLKID_DSPA_B			100
>>>>>> +#define CLKID_DSPB_A_SEL		101
>>>>>> +#define CLKID_DSPB_A_DIV		102
>>>>>> +#define CLKID_DSPB_A			103
>>>>>> +#define CLKID_DSPB_B_SEL		104
>>>>>> +#define CLKID_DSPB_B_DIV		105
>>>>>> +#define CLKID_DSPB_B			106
>>>>>> +#define CLKID_RTC_32K_CLKIN		107
>>>>>> +#define CLKID_RTC_32K_DIV		108
>>>>>> +#define CLKID_RTC_32K_XTAL		109
>>>>>> +#define CLKID_RTC_32K_SEL		110
>>>>>> +#define CLKID_CECB_32K_CLKIN		111
>>>>>> +#define CLKID_CECB_32K_DIV		112
>>>>>> +#define CLKID_CECB_32K_SEL_PRE		113
>>>>>> +#define CLKID_CECB_32K_SEL		114
>>>>>> +#define CLKID_CECA_32K_CLKIN		115
>>>>>> +#define CLKID_CECA_32K_DIV		116
>>>>>> +#define CLKID_CECA_32K_SEL_PRE		117
>>>>>> +#define CLKID_CECA_32K_SEL		118
>>>>>> +#define CLKID_DIV2_PRE			119
>>>>>> +#define CLKID_24M_DIV2			120
>>>>>> +#define CLKID_GEN_SEL			121
>>>>>> +#define CLKID_GEN_DIV			122
>>>>>> +#define CLKID_SARADC_DIV		123
>>>>>> +#define CLKID_PWM_A_SEL			124
>>>>>> +#define CLKID_PWM_A_DIV			125
>>>>>> +#define CLKID_PWM_B_SEL			126
>>>>>> +#define CLKID_PWM_B_DIV			127
>>>>>> +#define CLKID_PWM_C_SEL			128
>>>>>> +#define CLKID_PWM_C_DIV			129
>>>>>> +#define CLKID_PWM_D_SEL			130
>>>>>> +#define CLKID_PWM_D_DIV			131
>>>>>> +#define CLKID_PWM_E_SEL			132
>>>>>> +#define CLKID_PWM_E_DIV			133
>>>>>> +#define CLKID_PWM_F_SEL			134
>>>>>> +#define CLKID_PWM_F_DIV			135
>>>>>> +#define CLKID_SPICC_SEL			136
>>>>>> +#define CLKID_SPICC_DIV			137
>>>>>> +#define CLKID_SPICC_SEL2		138
>>>>>> +#define CLKID_TS_DIV			139
>>>>>> +#define CLKID_SPIFC_SEL			140
>>>>>> +#define CLKID_SPIFC_DIV			141
>>>>>> +#define CLKID_SPIFC_SEL2		142
>>>>>> +#define CLKID_USB_BUS_SEL		143
>>>>>> +#define CLKID_USB_BUS_DIV		144
>>>>>> +#define CLKID_SD_EMMC_SEL		145
>>>>>> +#define CLKID_SD_EMMC_DIV		146
>>>>>> +#define CLKID_SD_EMMC_SEL2		147
>>>>>> +#define CLKID_PSRAM_SEL			148
>>>>>> +#define CLKID_PSRAM_DIV			149
>>>>>> +#define CLKID_PSRAM_SEL2		150
>>>>>> +#define CLKID_DMC_SEL			151
>>>>>> +#define CLKID_DMC_DIV			152
>>>>>> +#define CLKID_DMC_SEL2			153
>>>>>> +#define NR_CLKS				154
>>>>>> +
>>>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>>>> +
>>>>>> +#endif /* __A1_H */
>>>>>
>>>>> .
>>>>>
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-13 14:21             ` Jian Hu
@ 2019-11-20  9:28               ` Jian Hu
  2019-11-20 15:35                 ` Jerome Brunet
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-20  9:28 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel

Hi, jerome

Is there any problem about fixed_pll_dco's parent_data?

Now both name and fw_name are described in parent_data.

More debug message is in the last email.

On 2019/11/13 22:21, Jian Hu wrote:
> 
> On 2019/11/13 0:59, Jerome Brunet wrote:
>>
>> On Sat 09 Nov 2019 at 12:16, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> Hi, Jerome
>>>
>>> Sorry for late rely
>>>
>>> On 2019/11/4 16:24, Jerome Brunet wrote:
>>>>
>>>> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> Hi, Jerome
>>>>>
>>>>> Thanks for your review
>>>>>
>>>>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>>>>
>>>>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>
>>>>>>> The Amlogic A1 clock includes three drivers:
>>>>>>> peripheral clocks, pll clocks, CPU clocks.
>>>>>>> sys pll and CPU clocks will be sent in next patch.
>>>>>>>
>>>>>>> Unlike the previous series, there is no EE/AO domain
>>>>>>> in A1 CLK controllers.
>>>>>>>
>>>>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>>>>> ---
>>>>>>>     drivers/clk/meson/Kconfig  |   10 +
>>>>>>>     drivers/clk/meson/Makefile |    1 +
>>>>>>>     drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>>>>     drivers/clk/meson/a1-pll.h |   56 ++
>>>>>>>     drivers/clk/meson/a1.c     | 2264 
>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>     drivers/clk/meson/a1.h     |  120 +++
>>>>>>>     6 files changed, 2796 insertions(+)
>>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.c
>>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.h
>>>>>>>     create mode 100644 drivers/clk/meson/a1.c
>>>>>>>     create mode 100644 drivers/clk/meson/a1.h
>>>>>>
>>>>>> In the next version, one
>>>>> OK, I will send a1 peripheral and pll driver in two patch.
>>>>>>
>>>>>>>
>>>>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>>>>> index dabeb43..c2809b2 100644
>>>>>>> --- a/drivers/clk/meson/Kconfig
>>>>>>> +++ b/drivers/clk/meson/Kconfig
>>>>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>>>>           Support for the audio clock controller on AmLogic A113D 
>>>>>>> devices,
>>>>>>>           aka axg, Say Y if you want audio subsystem to work.
>>>>>>>     +config COMMON_CLK_A1
>>>>>>> +    bool
>>>>>>> +    depends on ARCH_MESON
>>>>>>> +    select COMMON_CLK_MESON_REGMAP
>>>>>>> +    select COMMON_CLK_MESON_DUALDIV
>>>>>>> +    select COMMON_CLK_MESON_PLL
>>>>>>> +    help
>>>>>>> +      Support for the clock controller on Amlogic A113L device,
>>>>>>> +      aka a1. Say Y if you want peripherals to work.
>>>>>>> +
>>>>>>>     config COMMON_CLK_G12A
>>>>>>>         bool
>>>>>>>         depends on ARCH_MESON
>>>>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>>>>> index 3939f21..28cbae1 100644
>>>>>>> --- a/drivers/clk/meson/Makefile
>>>>>>> +++ b/drivers/clk/meson/Makefile
>>>>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += 
>>>>>>> vid-pll-div.o
>>>>>>>       obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>>>>     obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>>>>
>>>>>> So far, all the controller had there own option, I don't see why it
>>>>>> should be different here.
>>>>>>
>>>>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll 
>>>>> driver
>>>>>>>     obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>>>>     obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>>>>     obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..486d964
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>>>>> @@ -0,0 +1,345 @@
>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <linux/platform_device.h>
>>>>>>
>>>>>> Hum ... looks like some things are missing here
>>>>>>
>>>>>> #include <linux/of_device.h>
>>>>>> #include <linux/clk-provider.h>
>>>>>>
>>>>>> ?
>>>>> #1
>>>>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>>>>
>>>>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>>>>
>>>>> #2
>>>>> For A1 driver, the file "linux/of_device.h" is not required.
>>>>> It is required by meson-eeclk.c in fact.
>>>>
>>>> You are using what is provided by these headers directly in this file
>>>> If meson-eeclk ever changes, your driver breaks
>>>>
>>> OK, I will add the two header file.
>>>>>>
>>>>>>> +#include "clk-pll.h"
>>>>>>> +#include "meson-eeclk.h"
>>>>>>> +#include "a1-pll.h"
>>>>>>
>>>>>> Alphanumeric order please
>>>>>>
>>>>> OK, I will change it in the next version.
>>>>>
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>> +        .en = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +            .shift   = 28,
>>>>>>> +            .width   = 1,
>>>>>>> +        },
>>>>>>> +        .m = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +            .shift   = 0,
>>>>>>> +            .width   = 8,
>>>>>>> +        },
>>>>>>> +        .n = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +            .shift   = 10,
>>>>>>> +            .width   = 5,
>>>>>>> +        },
>>>>>>> +        .frac = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL1,
>>>>>>> +            .shift   = 0,
>>>>>>> +            .width   = 19,
>>>>>>> +        },
>>>>>>> +        .l = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +            .shift   = 31,
>>>>>>> +            .width   = 1,
>>>>>>> +        },
>>>>>>> +        .rst = {
>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +            .shift   = 29,
>>>>>>> +            .width   = 1,
>>>>>>> +        },
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fixed_pll_dco",
>>>>>>> +        .ops = &meson_clk_pll_ro_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>> +            .name = "xtal_fixpll",
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fixed_pll = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +        .bit_idx = 20,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "fixed_pll",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fixed_pll_dco.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * This clock is fclk_div2/3/4's parent,
>>>>>>> +         * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>>>>
>>>>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>>>>
>>>>>>> +         * It is required by the platform to operate correctly.
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>
>>>>>> Don't blindly copy/paste comments from other drivers. There is no 
>>>>>> driver
>>>>>> for the devices you are mentionning so the end of the comment is
>>>>>> confusing. The 3 first lines were enough
>>>>>>
>>>>> OK, I will remove the confusing comments
>>>>>
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>
>>>>>> >From your comment, I understand that some child are critical, not 
>>>>>> this
>>>>>> particular (or at least, not directly). So this can be removed AFAICT
>>>>>>
>>>>>> You should even need CLK_IGNORE_UNUSED for this one since the 
>>>>>> clock will
>>>>>> already be enabled before the late_init() kicks in
>>>>>>
>>>>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>>>>> +    .min = 32,
>>>>>>> +    .max = 64,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us 
>>>>>>> = 10 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us 
>>>>>>> = 40 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_hifi_pll = {
>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>> +        .en = {
>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>> +            .shift   = 28,
>>>>>>> +            .width   = 1,
>>>>>>> +        },
>>>>>>> +        .m = {
>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>> +            .shift   = 0,
>>>>>>> +            .width   = 8,
>>>>>>> +        },
>>>>>>> +        .n = {
>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>> +            .shift   = 10,
>>>>>>> +            .width   = 5,
>>>>>>> +        },
>>>>>>> +        .frac = {
>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>>>>> +            .shift   = 0,
>>>>>>> +            .width   = 19,
>>>>>>> +        },
>>>>>>> +        .l = {
>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_STS,
>>>>>>> +            .shift   = 31,
>>>>>>> +            .width   = 1,
>>>>>>> +        },
>>>>>>> +        .range = &a1_hifi_pll_mult_range,
>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>> +        .strict_sequence = true,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "hifi_pll",
>>>>>>> +        .ops = &meson_clk_pll_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>> +            .name = "xtal_fixpll",
>>>>>>
>>>>>> Both should provided when a controller transition from the old way of
>>>>>> describing parent to the new way. This is a new controller so it does
>>>>>> not apply.
>>>>> I do not understand why it does not apply, could you explain more?
>>>>
>>>> Your driver is new, it is not something old transitioning from global
>>>> name to clock in DT !
>>>>
>>>>>
>>>>> The xtal_fixpll clock is registered in another peripheral driver, 
>>>>> If do not
>>>>> desribe the "name" member in parent_data, "fw_name" does not work 
>>>>> because
>>>>> it has not been registered. the hifi_pll parent will be null in
>>>>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>>>>
>>>>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
>>>>
>>>> There will be an orphan yes, temporarily, until both controllers are 
>>>> up.
>>>> Once both controller are up, the clock will be reparented if necessary.
>>>>
>>>>>
>>>>> So both of "fw_name" of "name" should be described.
>>>>
>>>> No
>>>>
>>>
>>> #1
>>>
>>> Here, I am still confused.
>>>  From the point of view of the phenomenon, the name in parent_data is
>>> required.
>>>
>>>
>>> HIFI PLL is described like this:
>>>
>>>     .parent_data = &(const struct clk_parent_data){
>>>         .fw_name = "xtal_hifipll",
>>>         .name = "xtal_hifipll"
>>>     }
>>>
>>> Fixed PLL is described like this:
>>>
>>>     .parent_data = &(const struct clk_parent_data){
>>>         .fw_name = "xtal_fixpll",
>>>     },
>>>
>>> After the system boot completely, run cat
>>> /sys/kernel/debug/clk/clk_summary, Here is the result:
>>>
>>> # cat /sys/kernel/debug/clk/clk_summary
>>>                   enable  prepare  protect                    duty
>>>     clock         count   count    count  rate accuracy phase cycle
>>> --------------------------------------------------------------------
>>>   xtal            5        5        0    24000000    0     0  50000
>>>      ts_div       0        0        0    24000000    0     0  50000
>>>         ts        0        0        0    24000000    0     0  50000
>>>      pwm_f_sel    0        0        0    24000000    0     0  50000
>>>         pwm_f_div 0        0        0    24000000    0     0  50000
>>>            pwm_f  0        0        0    24000000    0     0  50000
>>> ......
>>>      xtal_syspll  0        0        0    24000000    0     0  50000
>>>      xtal_hifipll 0        0        0    24000000    0     0  50000
>>>         hifi_pll  0        0        0  1536000000    0     0  50000
>>>      xtal_usb_ctrl 0        0        0    24000000   0     0  50000
>>>      xtal_usb_phy  0        0        0    24000000   0     0  50000
>>>      xtal_fixpll   0        0        0    24000000   0     0  50000
>>>      xtal_clktree  0        0        0    24000000   0     0  50000
>>>   fixed_pll_dco    1        1        0         0   0     0  50000
>>
>> This means that CCF what not able to resolve the parent.
>> Either:
>> * you've made a mistake somewhere
>> * There is bug in CCF when the parent device is not available at probe
>> time, the clock is not properly reparented
>>
> 
> #1 Add DT describtion
> 
> DT description:
> 
> clkc_pll: pll-clock-controller {
>        compatible = "amlogic,a1-pll-clkc";
>        #clock-cells = <1>;
>        reg = <0 0x7c80 0 0x21c>;
>        clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
>              <&clkc_periphs CLKID_XTAL_HIFIPLL>;
>        clock-names = "xtal_fixpll", "xtal_hifipll";
> };
> 
> clkc_periphs: periphs-clock-controller {
>        compatible = "amlogic,a1-periphs-clkc";
>        #clock-cells = <1>;
>        reg = <0 0x800 0 0x104>;
>        clocks = <&clkc_pll CLKID_FCLK_DIV2>,
>                 <&clkc_pll CLKID_FCLK_DIV3>,
>                 <&clkc_pll CLKID_FCLK_DIV5>,
>                 <&clkc_pll CLKID_FCLK_DIV7>,
>                 <&clkc_pll CLKID_HIFI_PLL>,
>                 <&xtal>;
>        clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
>                      "fclk_div7", "hifi_pll", "xtal";
> };
> 
> And PLL clock driver probe first.
> 
> When register xtal_fixpll clock in periphs driver
> 
> it will walk the list of orphan clocks, it will try to get the orphan 
> parent.
> 
> the code path is :
> 
> struct clk_core *parent = __clk_init_parent(orphan)
> 
>    -> clk_core_get_parent_by_index(core, index)
> 
>     ->clk_core_fill_parent_index
> 
>      ->clk_core_get
> 
>       ->of_clk_get_hw_from_clkspec
> 
> In of_clk_get_hw_from_clkspec function, it will get hw_clk from 
> clk_provider, However the peripheral clock provider has not been
> added to "of_clk_providers" LIST, In other words, the peripheral clock
> provider does not exist at this time. (devm_of_clk_add_hw_provider has 
> not run)
> 
> So It will get parent failed from DT.
> 
> even if name is added in parent_data, PTR_ERR(parent) is not equal 
> -ENOENT, it will not run clk_core_lookup, the fixed_pll_dco is still a 
> orphan clock.
> 
> #2 Not add DT describtion
> 
> the code path is :
> 
> struct clk_core *parent = __clk_init_parent(orphan)
> 
>    -> clk_core_get_parent_by_index(core, index)
> 
>     ->clk_core_fill_parent_index
> 
>      ->clk_core_get
> 
>       ->clk_find_hw
> 
> clk_find_hw is used when the clock is registered by clk_register_clkdev
> 
> So it wlll get parented failed by clk_find_hw.
> 
> When name is described in parent_data, the parent will be found by
> 
> clk_core_lookup.
> 
> 
> In this scene,Only fw_name in parent_data, the orphan clock's parent 
> can not be found, But add the legacy name, the parent will be found.
> 
> #3
> When the provider has not been added to the CCF, And fw_name is alone in 
> parent_data in a orphan clock , How to get the orphan clock'parent ?
> It seems not supported.
> 
>> Either way, you'll have to debug a bit more
>>
>>>      fixed_pll     3        3        0         0   0     0  50000
>>>         fclk_div7_div 0     0        0         0   0     0  50000
>>> ....
>>>
>>> the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is 
>>> right.
>>>
>>> but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
>>> is zero.When the name in parent_data is added, its parent is 
>>> xtal_fixpll.
>>>
>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
>>> #
>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
>>> 0
>>>
>>>
>>> #2
>>> In  ./drivers/clk/qcom/gcc-sm8150.c
>>> For some clocks, Both fw_name and name are described in parent_data
>>> struct.
>>
>> Those are being migrated to DT description which means that we don't
>> know if the DT will the correct description
>>
>> In this case the clock framework will first try DT and if DT does
>> provide this fw_name, it will fallback to the legacy name.
>>
>> This is not your case as this is a new platform for which we know the DT
>> name exist.
>>
> It will get parent failed from DT as the previous says.
>>>
>>>>>
>>>>>>
>>>>>> Same for the other occurences.
>>>>>>
>>>>>> Also, I think you meant xtal_hifipll
>>>>> Yes,I will correct it.
>>>>>>
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>>>>> +    .mult = 1,
>>>>>>> +    .div = 2,
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div2_div",
>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fixed_pll.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +        .bit_idx = 21,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div2",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fclk_div2_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * This clock is used by DDR clock in BL2 firmware
>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>>>>> +    .mult = 1,
>>>>>>> +    .div = 3,
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div3_div",
>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fixed_pll.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +        .bit_idx = 22,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div3",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fclk_div3_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * This clock is used by APB bus which setted in Romcode
>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>>>>> +    .mult = 1,
>>>>>>> +    .div = 5,
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div5_div",
>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fixed_pll.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +        .bit_idx = 23,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div5",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fclk_div5_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * This clock is used by AXI bus which setted in Romcode
>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>>>>> +    .mult = 1,
>>>>>>> +    .div = 7,
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div7_div",
>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fixed_pll.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>> +        .bit_idx = 24,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "fclk_div7",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_fclk_div7_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* Array of all clocks provided by this provider */
>>>>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>>>>> +    .hws = {
>>>>>>> +        [CLKID_FIXED_PLL_DCO]        = &a1_fixed_pll_dco.hw,
>>>>>>> +        [CLKID_FIXED_PLL]        = &a1_fixed_pll.hw,
>>>>>>> +        [CLKID_HIFI_PLL]        = &a1_hifi_pll.hw,
>>>>>>> +        [CLKID_FCLK_DIV2]        = &a1_fclk_div2.hw,
>>>>>>> +        [CLKID_FCLK_DIV3]        = &a1_fclk_div3.hw,
>>>>>>> +        [CLKID_FCLK_DIV5]        = &a1_fclk_div5.hw,
>>>>>>> +        [CLKID_FCLK_DIV7]        = &a1_fclk_div7.hw,
>>>>>>> +        [CLKID_FCLK_DIV2_DIV]        = &a1_fclk_div2_div.hw,
>>>>>>> +        [CLKID_FCLK_DIV3_DIV]        = &a1_fclk_div3_div.hw,
>>>>>>> +        [CLKID_FCLK_DIV5_DIV]        = &a1_fclk_div5_div.hw,
>>>>>>> +        [CLKID_FCLK_DIV7_DIV]        = &a1_fclk_div7_div.hw,
>>>>>>> +        [NR_PLL_CLKS]            = NULL,
>>>>>>> +    },
>>>>>>> +    .num = NR_PLL_CLKS,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>>>>> +    &a1_fixed_pll_dco,
>>>>>>> +    &a1_fixed_pll,
>>>>>>> +    &a1_hifi_pll,
>>>>>>> +    &a1_fclk_div2,
>>>>>>> +    &a1_fclk_div3,
>>>>>>> +    &a1_fclk_div5,
>>>>>>> +    &a1_fclk_div7,
>>>>>>> +};
>>>>>>> +
>>>>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>>>>> +{
>>>>>>> +    int ret;
>>>>>>> +
>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>> +    if (ret)
>>>>>>> +        return ret;
>>>>>>> +
>>>>>>> +    return 0;
>>>>>>> +}
>>>>>>
>>>>>> This function is useless.
>>>>>>
>>>>> OK, I will use meson_eeclkc_probe derectly.
>>>>>>> +
>>>>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>>>>> +        .regmap_clks = a1_pll_regmaps,
>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>>>>> +        .hw_onecell_data = &a1_pll_hw_onecell_data,
>>>>>>> +};
>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>> +    {
>>>>>>> +        .compatible = "amlogic,a1-pll-clkc",
>>>>>>> +        .data = &a1_pll_data
>>>>>>> +    },
>>>>>>> +    { /* sentinel */ }
>>>>>>
>>>>>> Nitpick: don't need to write this, just write the line like this
>>>>>>
>>>>> OK, remove it.
>>>>>> ' }, {}'
>>>>>>
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>> +    .probe        = meson_a1_pll_probe,
>>>>>>> +    .driver        = {
>>>>>>> +        .name    = "a1-pll-clkc",
>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..99ee2a9
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>>>>> @@ -0,0 +1,56 @@
>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>> + */
>>>>>>> +
>>>>>>> +#ifndef __A1_PLL_H
>>>>>>> +#define __A1_PLL_H
>>>>>>> +
>>>>>>> +/* PLL register offset */
>>>>>>> +#define ANACTRL_FIXPLL_CTRL0        0x80
>>>>>>> +#define ANACTRL_FIXPLL_CTRL1        0x84
>>>>>>> +#define ANACTRL_FIXPLL_CTRL2        0x88
>>>>>>> +#define ANACTRL_FIXPLL_CTRL3        0x8c
>>>>>>> +#define ANACTRL_FIXPLL_CTRL4        0x90
>>>>>>> +#define ANACTRL_FIXPLL_STS        0x94
>>>>>>> +#define ANACTRL_SYSPLL_CTRL0        0x100
>>>>>>> +#define ANACTRL_SYSPLL_CTRL1        0x104
>>>>>>> +#define ANACTRL_SYSPLL_CTRL2        0x108
>>>>>>> +#define ANACTRL_SYSPLL_CTRL3        0x10c
>>>>>>> +#define ANACTRL_SYSPLL_CTRL4        0x110
>>>>>>> +#define ANACTRL_SYSPLL_STS        0x114
>>>>>>> +#define ANACTRL_HIFIPLL_CTRL0        0x140
>>>>>>> +#define ANACTRL_HIFIPLL_CTRL1        0x144
>>>>>>> +#define ANACTRL_HIFIPLL_CTRL2        0x148
>>>>>>> +#define ANACTRL_HIFIPLL_CTRL3        0x14c
>>>>>>> +#define ANACTRL_HIFIPLL_CTRL4        0x150
>>>>>>> +#define ANACTRL_HIFIPLL_STS        0x154
>>>>>>> +#define ANACTRL_AUDDDS_CTRL0        0x180
>>>>>>> +#define ANACTRL_AUDDDS_CTRL1        0x184
>>>>>>> +#define ANACTRL_AUDDDS_CTRL2        0x188
>>>>>>> +#define ANACTRL_AUDDDS_CTRL3        0x18c
>>>>>>> +#define ANACTRL_AUDDDS_CTRL4        0x190
>>>>>>> +#define ANACTRL_AUDDDS_STS        0x194
>>>>>>> +#define ANACTRL_MISCTOP_CTRL0        0x1c0
>>>>>>> +#define ANACTRL_POR_CNTL        0x208
>>>>>>> +
>>>>>>> +/*
>>>>>>> + * CLKID index values
>>>>>>> + *
>>>>>>> + * These indices are entirely contrived and do not map onto the 
>>>>>>> hardware.
>>>>>>> + * It has now been decided to expose everything by default in 
>>>>>>> the DT header:
>>>>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids 
>>>>>>> we don't want
>>>>>>> + * to expose, such as the internal muxes and dividers of 
>>>>>>> composite clocks,
>>>>>>> + * will remain defined here.
>>>>>>> + */
>>>>>>> +#define CLKID_FIXED_PLL_DCO        0
>>>>>>> +#define CLKID_FCLK_DIV2_DIV        2
>>>>>>> +#define CLKID_FCLK_DIV3_DIV        3
>>>>>>> +#define CLKID_FCLK_DIV5_DIV        4
>>>>>>> +#define CLKID_FCLK_DIV7_DIV        5
>>>>>>> +#define NR_PLL_CLKS            11
>>>>>>> +
>>>>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>>>>> +
>>>>>>> +#endif /* __A1_PLL_H */
>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..86a4733
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>> @@ -0,0 +1,2264 @@
>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <linux/platform_device.h>
>>>>>>> +#include "clk-pll.h"
>>>>>>> +#include "clk-dualdiv.h"
>>>>>>> +#include "meson-eeclk.h"
>>>>>>> +#include "a1.h"
>>>>>>
>>>>>> Same as above
>>>>> OK, I will change the order.
>>>>> In fact, the clk-pll.h is not used in the current driver.
>>>>> I will remove it.
>>>>>>
>>>>>>> +
>>>>>>> +/* PLLs clock in gates, its parent is xtal */
>>>>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>> +        .bit_idx = 0,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "xtal_clktree",
>>>>>>> +        .ops = &clk_regmap_gate_ro_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>> +            .fw_name = "xtal",
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * switch for xtal clock
>>>>>>> +         * Linux should not change it at runtime
>>>>>>> +         */
>>>>>>
>>>>>> Comment not useful: it uses the Ro ops
>>>>>>
>>>>> OK,  remove the comments
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>> +        .bit_idx = 1,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "xtal_fixpll",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>> +            .fw_name = "xtal",
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +        /*
>>>>>>> +         * it feeds DDR,AXI,APB bus
>>>>>>> +         * Linux should not change it at runtime
>>>>>>> +         */
>>>>>>
>>>>>> Again, the child are critical, not directly this clock from your
>>>>>> comment.
>>>>>>
>>>>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>>>>
>>>>> repace as clk_regmap_gate_ro_ops
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>
>>>>> [ ... ]
>>>>>
>>>>>>> +
>>>>>>> +/* dsp a clk */
>>>>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>>>>> +    { .fw_name = "xtal", },
>>>>>>> +    { .fw_name = "fclk_div2", },
>>>>>>> +    { .fw_name = "fclk_div3", },
>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>> +    { .fw_name = "hifi_pll", },
>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .mask = 0x7,
>>>>>>> +        .shift = 10,
>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspa_a_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>
>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>> Yes, I miss the flag.
>>>>>>
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 10,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspa_a_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_a_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_a = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .bit_idx = 13,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspa_a",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_a_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .mask = 0x7,
>>>>>>> +        .shift = 26,
>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspa_b_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>
>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>>
>>>>> Yes, I will add it.
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .shift = 16,
>>>>>>> +        .width = 10,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspa_b_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_b_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_b = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .bit_idx = 29,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspa_b",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_b_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 15,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspa_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>> +            { .hw = &a1_dspa_a.hw },
>>>>>>> +            { .hw = &a1_dspa_b.hw },
>>>>>>> +        },
>>>>>>> +        .num_parents = 2,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>> +        .bit_idx = 1,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspa_en_dspa",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>
>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>
>>>>> I should remove it
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>> +        .bit_idx = 0,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspa_en_nic",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspa_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>
>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>
>>>>> I should remove it
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>
>>>>>> Same question and remarks applies to DSP B
>>>>>>
>>>>> got it
>>>>>>> +/* dsp b clk */
>>>>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .mask = 0x7,
>>>>>>> +        .shift = 10,
>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspb_a_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 10,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspb_a_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_a_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_a = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .bit_idx = 13,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspb_a",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_a_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .mask = 0x7,
>>>>>>> +        .shift = 26,
>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspb_b_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .shift = 16,
>>>>>>> +        .width = 10,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspb_b_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_b_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_b = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .bit_idx = 29,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspb_b",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_b_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 15,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dspb_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_a.hw, &a1_dspb_b.hw,
>>>>>>> +        },
>>>>>>> +        .num_parents = 2,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>> +        .bit_idx = 1,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspb_en_dspb",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>> +        .bit_idx = 0,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dspb_en_nic",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dspb_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* 12M/24M clock */
>>>>>>> +static struct clk_regmap a1_24m = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = CLK12_24_CTRL,
>>>>>>> +        .bit_idx = 11,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "24m",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>> +            .fw_name = "xtal",
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>
>>>>> [ ... ]
>>>>>
>>>>>>> +static struct clk_regmap a1_saradc_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 9,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "saradc_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>> +            { .fw_name = "xtal", },
>>>>>>> +            { .hw = &a1_sys_clk.hw, },
>>>>>>> +        },
>>>>>>> +        .num_parents = 2,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_saradc_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "saradc_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_saradc_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_saradc_clk = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>> +        .bit_idx = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "saradc_clk",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_saradc_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm a/b/c/d parent data */
>>>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>>>> +    { .fw_name = "xtal", },
>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>> +};
>>>>>>
>>>>>> Looks like the same as SAR ADC
>>>>>>
>>>>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>>>>> +
>>>>>>> +/* pwm a clk */
>>>>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 9,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_a_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_a_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_a_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_a = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .bit_idx = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_a",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_a_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * The CPU working voltage is controlled by pwm_a
>>>>>>> +         * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>>>>> +         * to avoid changing at runtime.
>>>>>>                                        ^ it
>>>>>>
>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>                       "blabla. And" is strange
>>>>>>
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>
>>>>>> This only skips the late_init() disable of unused clocks
>>>>>>
>>>>>> Be aware that this is not fool-proof. If at any time a driver enable
>>>>>> then disable the clock, the clock will be disable and I guess your
>>>>>> platform will die if this provides the CPU voltage.
>>>>> OK, CLK_IS_CRITICAL is better.
>>>>>>
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm b clk */
>>>>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 25,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_b_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .shift = 16,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_b_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_b_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_b = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>> +        .bit_idx = 24,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_b",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_b_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm c clk */
>>>>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 9,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_c_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_c_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_c_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_c = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .bit_idx = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_c",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_c_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm d clk */
>>>>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 25,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_d_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .shift = 16,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_d_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_d_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_d = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>> +        .bit_idx = 24,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_d",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_d_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>>>>> +    { .fw_name = "xtal", },
>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm e clk */
>>>>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .mask = 0x3,
>>>>>>> +        .shift = 9,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_e_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_e_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_e_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_e = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .bit_idx = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_e",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_e_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* pwm f clk */
>>>>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .mask = 0x3,
>>>>>>> +        .shift = 25,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_f_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .shift = 16,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "pwm_f_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_f_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_pwm_f = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>> +        .bit_idx = 24,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "pwm_f",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_pwm_f_div.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>
>>>>> [ ... ]
>>>>>
>>>>>>> +
>>>>>>> +/* dmc clk */
>>>>>>> +static struct clk_regmap a1_dmc_sel = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>> +        .mask = 0x3,
>>>>>>> +        .shift = 9,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dmc_sel",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = sd_emmc_parents,
>>>>>>> +        .num_parents = 4,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dmc_div = {
>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>> +        .shift = 0,
>>>>>>> +        .width = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dmc_div",
>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dmc_sel.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>> +        .mask = 0x1,
>>>>>>> +        .shift = 15,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "dmc_sel2",
>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>> +            { .hw = &a1_dmc_div.hw },
>>>>>>> +            { .fw_name = "xtal", },
>>>>>>> +        },
>>>>>>> +        .num_parents = 2,
>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct clk_regmap a1_dmc = {
>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>> +        .bit_idx = 8,
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>> +        .name = "dmc",
>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_dmc_sel2.hw
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        /*
>>>>>>> +         * This clock is used by DDR clock which setted in BL2
>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>> +         * Until the following condition are met, we need this 
>>>>>>> clock to
>>>>>>> +         * be marked as critical:
>>>>>>> +         * a) Mark the clock used by a firmware resource, if 
>>>>>>> possible
>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the 
>>>>>>> sure the
>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>> +         */
>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>
>>>>>> Should you put all this DMC stuff in RO until you got a driver for 
>>>>>> it ?
>>>>> OK, replace as clk_regmap_gate_ro_ops
>>>>>>
>>>>> [ ... ]
>>>>>>> +
>>>>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>>>>> +{
>>>>>>> +    int ret;
>>>>>>> +
>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>> +    if (ret)
>>>>>>> +        return ret;
>>>>>>> +
>>>>>>> +    return 0;
>>>>>>> +}
>>>>>>
>>>>>> Again this function is function is useless and it makes me wonder 
>>>>>> if you
>>>>>> should really be using meson_eeclkc_probe()
>>>>>>
>>>>>> This makes you use syscon which is not correct unless you have a good
>>>>>> reason ?
>>>>>>
>>>>> If it can not use the meson_eeclkc_probe(), I will realize a probe 
>>>>> function
>>>>> which is mostly duplicate with meson_eeclkc_probe() except
>>>>> "syscon_node_to_regmap"
>>>>>
>>>>> Maybe another common probe function and a new file are required for A1
>>>>> three drivers? (include the CPU clock driver)
>>>>
>>>> Maybe
>>>>
>>> I will add a new function base on meson-eeclk.c
>>>>>
>>>>> Or using meson_eeclkc_probe is more easier?
>>>>
>>>> It is not question of easiness, but correctness.
>>>>
>>>>>
>>>>>> Is there anything but clocks and resets in these register region ?
>>>>> No, there is only clocks in the register region.
>>>>> the same does the PLL register region.
>>>>
>>>> Then there is no reason to use syscon for those drivers
>>>> Add a new probe function for A1
>>>>>>
>>>>>>> +
>>>>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>>>>> +        .regmap_clks = a1_periphs_regmaps,
>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>>>>> +        .hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>>>>> +};
>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>> +    {
>>>>>>> +        .compatible = "amlogic,a1-periphs-clkc",
>>>>>>> +        .data = &a1_periphs_data
>>>>>>> +    },
>>>>>>> +    { /* sentinel */ }
>>>>>>> +};
>>>>>>> +
>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>> +    .probe        = meson_a1_periphs_probe,
>>>>>>> +    .driver        = {
>>>>>>> +        .name    = "a1-periphs-clkc",
>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..1ae5e04
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/meson/a1.h
>>>>>>> @@ -0,0 +1,120 @@
>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>> + */
>>>>>>> +
>>>>>>> +#ifndef __A1_H
>>>>>>> +#define __A1_H
>>>>>>> +
>>>>>>> +/* peripheral clock controller register offset */
>>>>>>> +#define SYS_OSCIN_CTRL            0x0
>>>>>>> +#define RTC_BY_OSCIN_CTRL0        0x4
>>>>>>> +#define RTC_BY_OSCIN_CTRL1        0x8
>>>>>>> +#define RTC_CTRL            0xc
>>>>>>> +#define SYS_CLK_CTRL0            0x10
>>>>>>> +#define AXI_CLK_CTRL0            0x14
>>>>>>> +#define SYS_CLK_EN0            0x1c
>>>>>>> +#define SYS_CLK_EN1            0x20
>>>>>>> +#define AXI_CLK_EN            0x24
>>>>>>> +#define DSPA_CLK_EN            0x28
>>>>>>> +#define DSPB_CLK_EN            0x2c
>>>>>>> +#define DSPA_CLK_CTRL0            0x30
>>>>>>> +#define DSPB_CLK_CTRL0            0x34
>>>>>>> +#define CLK12_24_CTRL            0x38
>>>>>>> +#define GEN_CLK_CTRL            0x3c
>>>>>>> +#define TIMESTAMP_CTRL0            0x40
>>>>>>> +#define TIMESTAMP_CTRL1            0x44
>>>>>>> +#define TIMESTAMP_CTRL2            0x48
>>>>>>> +#define TIMESTAMP_VAL0            0x4c
>>>>>>> +#define TIMESTAMP_VAL1            0x50
>>>>>>> +#define TIMEBASE_CTRL0            0x54
>>>>>>> +#define TIMEBASE_CTRL1            0x58
>>>>>>> +#define SAR_ADC_CLK_CTRL        0xc0
>>>>>>> +#define PWM_CLK_AB_CTRL            0xc4
>>>>>>> +#define PWM_CLK_CD_CTRL            0xc8
>>>>>>> +#define PWM_CLK_EF_CTRL            0xcc
>>>>>>> +#define SPICC_CLK_CTRL            0xd0
>>>>>>> +#define TS_CLK_CTRL            0xd4
>>>>>>> +#define SPIFC_CLK_CTRL            0xd8
>>>>>>> +#define USB_BUSCLK_CTRL            0xdc
>>>>>>> +#define SD_EMMC_CLK_CTRL        0xe0
>>>>>>> +#define CECA_CLK_CTRL0            0xe4
>>>>>>> +#define CECA_CLK_CTRL1            0xe8
>>>>>>> +#define CECB_CLK_CTRL0            0xec
>>>>>>> +#define CECB_CLK_CTRL1            0xf0
>>>>>>> +#define PSRAM_CLK_CTRL            0xf4
>>>>>>> +#define DMC_CLK_CTRL            0xf8
>>>>>>> +#define FCLK_DIV1_SEL            0xfc
>>>>>>> +#define TST_CTRL            0x100
>>>>>>> +
>>>>>>> +#define CLKID_XTAL_CLKTREE        0
>>>>>>> +#define CLKID_SYS_A_SEL            89
>>>>>>> +#define CLKID_SYS_A_DIV            90
>>>>>>> +#define CLKID_SYS_A            91
>>>>>>> +#define CLKID_SYS_B_SEL            92
>>>>>>> +#define CLKID_SYS_B_DIV            93
>>>>>>> +#define CLKID_SYS_B            94
>>>>>>> +#define CLKID_DSPA_A_SEL        95
>>>>>>> +#define CLKID_DSPA_A_DIV        96
>>>>>>> +#define CLKID_DSPA_A            97
>>>>>>> +#define CLKID_DSPA_B_SEL        98
>>>>>>> +#define CLKID_DSPA_B_DIV        99
>>>>>>> +#define CLKID_DSPA_B            100
>>>>>>> +#define CLKID_DSPB_A_SEL        101
>>>>>>> +#define CLKID_DSPB_A_DIV        102
>>>>>>> +#define CLKID_DSPB_A            103
>>>>>>> +#define CLKID_DSPB_B_SEL        104
>>>>>>> +#define CLKID_DSPB_B_DIV        105
>>>>>>> +#define CLKID_DSPB_B            106
>>>>>>> +#define CLKID_RTC_32K_CLKIN        107
>>>>>>> +#define CLKID_RTC_32K_DIV        108
>>>>>>> +#define CLKID_RTC_32K_XTAL        109
>>>>>>> +#define CLKID_RTC_32K_SEL        110
>>>>>>> +#define CLKID_CECB_32K_CLKIN        111
>>>>>>> +#define CLKID_CECB_32K_DIV        112
>>>>>>> +#define CLKID_CECB_32K_SEL_PRE        113
>>>>>>> +#define CLKID_CECB_32K_SEL        114
>>>>>>> +#define CLKID_CECA_32K_CLKIN        115
>>>>>>> +#define CLKID_CECA_32K_DIV        116
>>>>>>> +#define CLKID_CECA_32K_SEL_PRE        117
>>>>>>> +#define CLKID_CECA_32K_SEL        118
>>>>>>> +#define CLKID_DIV2_PRE            119
>>>>>>> +#define CLKID_24M_DIV2            120
>>>>>>> +#define CLKID_GEN_SEL            121
>>>>>>> +#define CLKID_GEN_DIV            122
>>>>>>> +#define CLKID_SARADC_DIV        123
>>>>>>> +#define CLKID_PWM_A_SEL            124
>>>>>>> +#define CLKID_PWM_A_DIV            125
>>>>>>> +#define CLKID_PWM_B_SEL            126
>>>>>>> +#define CLKID_PWM_B_DIV            127
>>>>>>> +#define CLKID_PWM_C_SEL            128
>>>>>>> +#define CLKID_PWM_C_DIV            129
>>>>>>> +#define CLKID_PWM_D_SEL            130
>>>>>>> +#define CLKID_PWM_D_DIV            131
>>>>>>> +#define CLKID_PWM_E_SEL            132
>>>>>>> +#define CLKID_PWM_E_DIV            133
>>>>>>> +#define CLKID_PWM_F_SEL            134
>>>>>>> +#define CLKID_PWM_F_DIV            135
>>>>>>> +#define CLKID_SPICC_SEL            136
>>>>>>> +#define CLKID_SPICC_DIV            137
>>>>>>> +#define CLKID_SPICC_SEL2        138
>>>>>>> +#define CLKID_TS_DIV            139
>>>>>>> +#define CLKID_SPIFC_SEL            140
>>>>>>> +#define CLKID_SPIFC_DIV            141
>>>>>>> +#define CLKID_SPIFC_SEL2        142
>>>>>>> +#define CLKID_USB_BUS_SEL        143
>>>>>>> +#define CLKID_USB_BUS_DIV        144
>>>>>>> +#define CLKID_SD_EMMC_SEL        145
>>>>>>> +#define CLKID_SD_EMMC_DIV        146
>>>>>>> +#define CLKID_SD_EMMC_SEL2        147
>>>>>>> +#define CLKID_PSRAM_SEL            148
>>>>>>> +#define CLKID_PSRAM_DIV            149
>>>>>>> +#define CLKID_PSRAM_SEL2        150
>>>>>>> +#define CLKID_DMC_SEL            151
>>>>>>> +#define CLKID_DMC_DIV            152
>>>>>>> +#define CLKID_DMC_SEL2            153
>>>>>>> +#define NR_CLKS                154
>>>>>>> +
>>>>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>>>>> +
>>>>>>> +#endif /* __A1_H */
>>>>>>
>>>>>> .
>>>>>>
>>>>
>>>> .
>>>>
>>
>> .
>>

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-20  9:28               ` Jian Hu
@ 2019-11-20 15:35                 ` Jerome Brunet
  2019-11-21  3:21                   ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-11-20 15:35 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, jerome
>
> Is there any problem about fixed_pll_dco's parent_data?
>
> Now both name and fw_name are described in parent_data.

Yes, there is a problem.  This approach is incorrect, as I've tried to
explain a couple times already. Let me try to re-summarize why this
approach is incorrect.

Both fw_name and name should be provided when it is possible that
the DT does not describe the input clock. IOW, it is only for controllers
which relied on the global name so far and are now starting to describe
the clock input in DT

This is not your case.
Your controller is new and DT will have the correct
info

You are trying work around an ordering issue by providing both fw_name
and name. This is not correct and I'll continue to nack it.

If the orphan clock is not reparented as you would expect, I suggest you
try to look a bit further at how the reparenting of orphans is done in
CCF and why it does not match your expectation.

>
> More debug message is in the last email.
>
> On 2019/11/13 22:21, Jian Hu wrote:
>>
>> On 2019/11/13 0:59, Jerome Brunet wrote:
>>>
>>> On Sat 09 Nov 2019 at 12:16, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> Hi, Jerome
>>>>
>>>> Sorry for late rely
>>>>
>>>> On 2019/11/4 16:24, Jerome Brunet wrote:
>>>>>
>>>>> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>
>>>>>> Hi, Jerome
>>>>>>
>>>>>> Thanks for your review
>>>>>>
>>>>>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>>>>>
>>>>>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>>
>>>>>>>> The Amlogic A1 clock includes three drivers:
>>>>>>>> peripheral clocks, pll clocks, CPU clocks.
>>>>>>>> sys pll and CPU clocks will be sent in next patch.
>>>>>>>>
>>>>>>>> Unlike the previous series, there is no EE/AO domain
>>>>>>>> in A1 CLK controllers.
>>>>>>>>
>>>>>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>>>>>> ---
>>>>>>>>     drivers/clk/meson/Kconfig  |   10 +
>>>>>>>>     drivers/clk/meson/Makefile |    1 +
>>>>>>>>     drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>>>>>     drivers/clk/meson/a1-pll.h |   56 ++
>>>>>>>>     drivers/clk/meson/a1.c     | 2264
>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>     drivers/clk/meson/a1.h     |  120 +++
>>>>>>>>     6 files changed, 2796 insertions(+)
>>>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.c
>>>>>>>>     create mode 100644 drivers/clk/meson/a1-pll.h
>>>>>>>>     create mode 100644 drivers/clk/meson/a1.c
>>>>>>>>     create mode 100644 drivers/clk/meson/a1.h
>>>>>>>
>>>>>>> In the next version, one
>>>>>> OK, I will send a1 peripheral and pll driver in two patch.
>>>>>>>
>>>>>>>>
>>>>>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>>>>>> index dabeb43..c2809b2 100644
>>>>>>>> --- a/drivers/clk/meson/Kconfig
>>>>>>>> +++ b/drivers/clk/meson/Kconfig
>>>>>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>>>>>           Support for the audio clock controller on AmLogic A113D
>>>>>>>> devices,
>>>>>>>>           aka axg, Say Y if you want audio subsystem to work.
>>>>>>>>     +config COMMON_CLK_A1
>>>>>>>> +    bool
>>>>>>>> +    depends on ARCH_MESON
>>>>>>>> +    select COMMON_CLK_MESON_REGMAP
>>>>>>>> +    select COMMON_CLK_MESON_DUALDIV
>>>>>>>> +    select COMMON_CLK_MESON_PLL
>>>>>>>> +    help
>>>>>>>> +      Support for the clock controller on Amlogic A113L device,
>>>>>>>> +      aka a1. Say Y if you want peripherals to work.
>>>>>>>> +
>>>>>>>>     config COMMON_CLK_G12A
>>>>>>>>         bool
>>>>>>>>         depends on ARCH_MESON
>>>>>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>>>>>> index 3939f21..28cbae1 100644
>>>>>>>> --- a/drivers/clk/meson/Makefile
>>>>>>>> +++ b/drivers/clk/meson/Makefile
>>>>>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) +=
>>>>>>>> vid-pll-div.o
>>>>>>>>       obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>>>>>     obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>>>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>>>>>
>>>>>>> So far, all the controller had there own option, I don't see why it
>>>>>>> should be different here.
>>>>>>>
>>>>>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll
>>>>>> driver
>>>>>>>>     obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>>>>>     obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>>>>>     obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>>>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..486d964
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>>>>>> @@ -0,0 +1,345 @@
>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>
>>>>>>> Hum ... looks like some things are missing here
>>>>>>>
>>>>>>> #include <linux/of_device.h>
>>>>>>> #include <linux/clk-provider.h>
>>>>>>>
>>>>>>> ?
>>>>>> #1
>>>>>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>>>>>
>>>>>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>>>>>
>>>>>> #2
>>>>>> For A1 driver, the file "linux/of_device.h" is not required.
>>>>>> It is required by meson-eeclk.c in fact.
>>>>>
>>>>> You are using what is provided by these headers directly in this file
>>>>> If meson-eeclk ever changes, your driver breaks
>>>>>
>>>> OK, I will add the two header file.
>>>>>>>
>>>>>>>> +#include "clk-pll.h"
>>>>>>>> +#include "meson-eeclk.h"
>>>>>>>> +#include "a1-pll.h"
>>>>>>>
>>>>>>> Alphanumeric order please
>>>>>>>
>>>>>> OK, I will change it in the next version.
>>>>>>
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>>> +        .en = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +            .shift   = 28,
>>>>>>>> +            .width   = 1,
>>>>>>>> +        },
>>>>>>>> +        .m = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +            .shift   = 0,
>>>>>>>> +            .width   = 8,
>>>>>>>> +        },
>>>>>>>> +        .n = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +            .shift   = 10,
>>>>>>>> +            .width   = 5,
>>>>>>>> +        },
>>>>>>>> +        .frac = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL1,
>>>>>>>> +            .shift   = 0,
>>>>>>>> +            .width   = 19,
>>>>>>>> +        },
>>>>>>>> +        .l = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +            .shift   = 31,
>>>>>>>> +            .width   = 1,
>>>>>>>> +        },
>>>>>>>> +        .rst = {
>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +            .shift   = 29,
>>>>>>>> +            .width   = 1,
>>>>>>>> +        },
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fixed_pll_dco",
>>>>>>>> +        .ops = &meson_clk_pll_ro_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>>> +            .name = "xtal_fixpll",
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fixed_pll = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +        .bit_idx = 20,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "fixed_pll",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fixed_pll_dco.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * This clock is fclk_div2/3/4's parent,
>>>>>>>> +         * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>>>>>
>>>>>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>>>>>
>>>>>>>> +         * It is required by the platform to operate correctly.
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>
>>>>>>> Don't blindly copy/paste comments from other drivers. There is no
>>>>>>> driver
>>>>>>> for the devices you are mentionning so the end of the comment is
>>>>>>> confusing. The 3 first lines were enough
>>>>>>>
>>>>>> OK, I will remove the confusing comments
>>>>>>
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>
>>>>>>> >From your comment, I understand that some child are critical, not
>>>>>>> this
>>>>>>> particular (or at least, not directly). So this can be removed AFAICT
>>>>>>>
>>>>>>> You should even need CLK_IGNORE_UNUSED for this one since the clock
>>>>>>> will
>>>>>>> already be enabled before the late_init() kicks in
>>>>>>>
>>>>>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>>>>>> +    .min = 32,
>>>>>>>> +    .max = 64,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us =
>>>>>>>> 10 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us =
>>>>>>>> 40 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_hifi_pll = {
>>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>>> +        .en = {
>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>> +            .shift   = 28,
>>>>>>>> +            .width   = 1,
>>>>>>>> +        },
>>>>>>>> +        .m = {
>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>> +            .shift   = 0,
>>>>>>>> +            .width   = 8,
>>>>>>>> +        },
>>>>>>>> +        .n = {
>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>> +            .shift   = 10,
>>>>>>>> +            .width   = 5,
>>>>>>>> +        },
>>>>>>>> +        .frac = {
>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>>>>>> +            .shift   = 0,
>>>>>>>> +            .width   = 19,
>>>>>>>> +        },
>>>>>>>> +        .l = {
>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_STS,
>>>>>>>> +            .shift   = 31,
>>>>>>>> +            .width   = 1,
>>>>>>>> +        },
>>>>>>>> +        .range = &a1_hifi_pll_mult_range,
>>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>>> +        .strict_sequence = true,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "hifi_pll",
>>>>>>>> +        .ops = &meson_clk_pll_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>>> +            .name = "xtal_fixpll",
>>>>>>>
>>>>>>> Both should provided when a controller transition from the old way of
>>>>>>> describing parent to the new way. This is a new controller so it does
>>>>>>> not apply.
>>>>>> I do not understand why it does not apply, could you explain more?
>>>>>
>>>>> Your driver is new, it is not something old transitioning from global
>>>>> name to clock in DT !
>>>>>
>>>>>>
>>>>>> The xtal_fixpll clock is registered in another peripheral driver, If
>>>>>> do not
>>>>>> desribe the "name" member in parent_data, "fw_name" does not work
>>>>>> because
>>>>>> it has not been registered. the hifi_pll parent will be null in
>>>>>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>>>>>
>>>>>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
>>>>>
>>>>> There will be an orphan yes, temporarily, until both controllers are
>>>>> up.
>>>>> Once both controller are up, the clock will be reparented if necessary.
>>>>>
>>>>>>
>>>>>> So both of "fw_name" of "name" should be described.
>>>>>
>>>>> No
>>>>>
>>>>
>>>> #1
>>>>
>>>> Here, I am still confused.
>>>>  From the point of view of the phenomenon, the name in parent_data is
>>>> required.
>>>>
>>>>
>>>> HIFI PLL is described like this:
>>>>
>>>>     .parent_data = &(const struct clk_parent_data){
>>>>         .fw_name = "xtal_hifipll",
>>>>         .name = "xtal_hifipll"
>>>>     }
>>>>
>>>> Fixed PLL is described like this:
>>>>
>>>>     .parent_data = &(const struct clk_parent_data){
>>>>         .fw_name = "xtal_fixpll",
>>>>     },
>>>>
>>>> After the system boot completely, run cat
>>>> /sys/kernel/debug/clk/clk_summary, Here is the result:
>>>>
>>>> # cat /sys/kernel/debug/clk/clk_summary
>>>>                   enable  prepare  protect                    duty
>>>>     clock         count   count    count  rate accuracy phase cycle
>>>> --------------------------------------------------------------------
>>>>   xtal            5        5        0    24000000    0     0  50000
>>>>      ts_div       0        0        0    24000000    0     0  50000
>>>>         ts        0        0        0    24000000    0     0  50000
>>>>      pwm_f_sel    0        0        0    24000000    0     0  50000
>>>>         pwm_f_div 0        0        0    24000000    0     0  50000
>>>>            pwm_f  0        0        0    24000000    0     0  50000
>>>> ......
>>>>      xtal_syspll  0        0        0    24000000    0     0  50000
>>>>      xtal_hifipll 0        0        0    24000000    0     0  50000
>>>>         hifi_pll  0        0        0  1536000000    0     0  50000
>>>>      xtal_usb_ctrl 0        0        0    24000000   0     0  50000
>>>>      xtal_usb_phy  0        0        0    24000000   0     0  50000
>>>>      xtal_fixpll   0        0        0    24000000   0     0  50000
>>>>      xtal_clktree  0        0        0    24000000   0     0  50000
>>>>   fixed_pll_dco    1        1        0         0   0     0  50000
>>>
>>> This means that CCF what not able to resolve the parent.
>>> Either:
>>> * you've made a mistake somewhere
>>> * There is bug in CCF when the parent device is not available at probe
>>> time, the clock is not properly reparented
>>>
>>
>> #1 Add DT describtion
>>
>> DT description:
>>
>> clkc_pll: pll-clock-controller {
>>        compatible = "amlogic,a1-pll-clkc";
>>        #clock-cells = <1>;
>>        reg = <0 0x7c80 0 0x21c>;
>>        clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
>>              <&clkc_periphs CLKID_XTAL_HIFIPLL>;
>>        clock-names = "xtal_fixpll", "xtal_hifipll";
>> };
>>
>> clkc_periphs: periphs-clock-controller {
>>        compatible = "amlogic,a1-periphs-clkc";
>>        #clock-cells = <1>;
>>        reg = <0 0x800 0 0x104>;
>>        clocks = <&clkc_pll CLKID_FCLK_DIV2>,
>>                 <&clkc_pll CLKID_FCLK_DIV3>,
>>                 <&clkc_pll CLKID_FCLK_DIV5>,
>>                 <&clkc_pll CLKID_FCLK_DIV7>,
>>                 <&clkc_pll CLKID_HIFI_PLL>,
>>                 <&xtal>;
>>        clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
>>                      "fclk_div7", "hifi_pll", "xtal";
>> };
>>
>> And PLL clock driver probe first.
>>
>> When register xtal_fixpll clock in periphs driver
>>
>> it will walk the list of orphan clocks, it will try to get the orphan
>> parent.
>>
>> the code path is :
>>
>> struct clk_core *parent = __clk_init_parent(orphan)
>>
>>    -> clk_core_get_parent_by_index(core, index)
>>
>>     ->clk_core_fill_parent_index
>>
>>      ->clk_core_get
>>
>>       ->of_clk_get_hw_from_clkspec
>>
>> In of_clk_get_hw_from_clkspec function, it will get hw_clk from
>> clk_provider, However the peripheral clock provider has not been
>> added to "of_clk_providers" LIST, In other words, the peripheral clock
>> provider does not exist at this time. (devm_of_clk_add_hw_provider has
>> not run)
>>
>> So It will get parent failed from DT.
>>
>> even if name is added in parent_data, PTR_ERR(parent) is not equal
>> -ENOENT, it will not run clk_core_lookup, the fixed_pll_dco is still a
>> orphan clock.
>>
>> #2 Not add DT describtion
>>
>> the code path is :
>>
>> struct clk_core *parent = __clk_init_parent(orphan)
>>
>>    -> clk_core_get_parent_by_index(core, index)
>>
>>     ->clk_core_fill_parent_index
>>
>>      ->clk_core_get
>>
>>       ->clk_find_hw
>>
>> clk_find_hw is used when the clock is registered by clk_register_clkdev
>>
>> So it wlll get parented failed by clk_find_hw.
>>
>> When name is described in parent_data, the parent will be found by
>>
>> clk_core_lookup.
>>
>>
>> In this scene,Only fw_name in parent_data, the orphan clock's parent can
>> not be found, But add the legacy name, the parent will be found.
>>
>> #3
>> When the provider has not been added to the CCF, And fw_name is alone in
>> parent_data in a orphan clock , How to get the orphan clock'parent ?
>> It seems not supported.
>>
>>> Either way, you'll have to debug a bit more
>>>
>>>>      fixed_pll     3        3        0         0   0     0  50000
>>>>         fclk_div7_div 0     0        0         0   0     0  50000
>>>> ....
>>>>
>>>> the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is
>>>> right.
>>>>
>>>> but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
>>>> is zero.When the name in parent_data is added, its parent is
>>>> xtal_fixpll.
>>>>
>>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
>>>> #
>>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
>>>> 0
>>>>
>>>>
>>>> #2
>>>> In  ./drivers/clk/qcom/gcc-sm8150.c
>>>> For some clocks, Both fw_name and name are described in parent_data
>>>> struct.
>>>
>>> Those are being migrated to DT description which means that we don't
>>> know if the DT will the correct description
>>>
>>> In this case the clock framework will first try DT and if DT does
>>> provide this fw_name, it will fallback to the legacy name.
>>>
>>> This is not your case as this is a new platform for which we know the DT
>>> name exist.
>>>
>> It will get parent failed from DT as the previous says.
>>>>
>>>>>>
>>>>>>>
>>>>>>> Same for the other occurences.
>>>>>>>
>>>>>>> Also, I think you meant xtal_hifipll
>>>>>> Yes,I will correct it.
>>>>>>>
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>>>>>> +    .mult = 1,
>>>>>>>> +    .div = 2,
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div2_div",
>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +        .bit_idx = 21,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div2",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fclk_div2_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * This clock is used by DDR clock in BL2 firmware
>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>>>>>> +    .mult = 1,
>>>>>>>> +    .div = 3,
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div3_div",
>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +        .bit_idx = 22,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div3",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fclk_div3_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * This clock is used by APB bus which setted in Romcode
>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>>>>>> +    .mult = 1,
>>>>>>>> +    .div = 5,
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div5_div",
>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +        .bit_idx = 23,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div5",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fclk_div5_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * This clock is used by AXI bus which setted in Romcode
>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>>>>>> +    .mult = 1,
>>>>>>>> +    .div = 7,
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div7_div",
>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>> +        .bit_idx = 24,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "fclk_div7",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_fclk_div7_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* Array of all clocks provided by this provider */
>>>>>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>>>>>> +    .hws = {
>>>>>>>> +        [CLKID_FIXED_PLL_DCO]        = &a1_fixed_pll_dco.hw,
>>>>>>>> +        [CLKID_FIXED_PLL]        = &a1_fixed_pll.hw,
>>>>>>>> +        [CLKID_HIFI_PLL]        = &a1_hifi_pll.hw,
>>>>>>>> +        [CLKID_FCLK_DIV2]        = &a1_fclk_div2.hw,
>>>>>>>> +        [CLKID_FCLK_DIV3]        = &a1_fclk_div3.hw,
>>>>>>>> +        [CLKID_FCLK_DIV5]        = &a1_fclk_div5.hw,
>>>>>>>> +        [CLKID_FCLK_DIV7]        = &a1_fclk_div7.hw,
>>>>>>>> +        [CLKID_FCLK_DIV2_DIV]        = &a1_fclk_div2_div.hw,
>>>>>>>> +        [CLKID_FCLK_DIV3_DIV]        = &a1_fclk_div3_div.hw,
>>>>>>>> +        [CLKID_FCLK_DIV5_DIV]        = &a1_fclk_div5_div.hw,
>>>>>>>> +        [CLKID_FCLK_DIV7_DIV]        = &a1_fclk_div7_div.hw,
>>>>>>>> +        [NR_PLL_CLKS]            = NULL,
>>>>>>>> +    },
>>>>>>>> +    .num = NR_PLL_CLKS,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>>>>>> +    &a1_fixed_pll_dco,
>>>>>>>> +    &a1_fixed_pll,
>>>>>>>> +    &a1_hifi_pll,
>>>>>>>> +    &a1_fclk_div2,
>>>>>>>> +    &a1_fclk_div3,
>>>>>>>> +    &a1_fclk_div5,
>>>>>>>> +    &a1_fclk_div7,
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> +    int ret;
>>>>>>>> +
>>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>>> +    if (ret)
>>>>>>>> +        return ret;
>>>>>>>> +
>>>>>>>> +    return 0;
>>>>>>>> +}
>>>>>>>
>>>>>>> This function is useless.
>>>>>>>
>>>>>> OK, I will use meson_eeclkc_probe derectly.
>>>>>>>> +
>>>>>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>>>>>> +        .regmap_clks = a1_pll_regmaps,
>>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>>>>>> +        .hw_onecell_data = &a1_pll_hw_onecell_data,
>>>>>>>> +};
>>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>>> +    {
>>>>>>>> +        .compatible = "amlogic,a1-pll-clkc",
>>>>>>>> +        .data = &a1_pll_data
>>>>>>>> +    },
>>>>>>>> +    { /* sentinel */ }
>>>>>>>
>>>>>>> Nitpick: don't need to write this, just write the line like this
>>>>>>>
>>>>>> OK, remove it.
>>>>>>> ' }, {}'
>>>>>>>
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>>> +    .probe        = meson_a1_pll_probe,
>>>>>>>> +    .driver        = {
>>>>>>>> +        .name    = "a1-pll-clkc",
>>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..99ee2a9
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>>>>>> @@ -0,0 +1,56 @@
>>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#ifndef __A1_PLL_H
>>>>>>>> +#define __A1_PLL_H
>>>>>>>> +
>>>>>>>> +/* PLL register offset */
>>>>>>>> +#define ANACTRL_FIXPLL_CTRL0        0x80
>>>>>>>> +#define ANACTRL_FIXPLL_CTRL1        0x84
>>>>>>>> +#define ANACTRL_FIXPLL_CTRL2        0x88
>>>>>>>> +#define ANACTRL_FIXPLL_CTRL3        0x8c
>>>>>>>> +#define ANACTRL_FIXPLL_CTRL4        0x90
>>>>>>>> +#define ANACTRL_FIXPLL_STS        0x94
>>>>>>>> +#define ANACTRL_SYSPLL_CTRL0        0x100
>>>>>>>> +#define ANACTRL_SYSPLL_CTRL1        0x104
>>>>>>>> +#define ANACTRL_SYSPLL_CTRL2        0x108
>>>>>>>> +#define ANACTRL_SYSPLL_CTRL3        0x10c
>>>>>>>> +#define ANACTRL_SYSPLL_CTRL4        0x110
>>>>>>>> +#define ANACTRL_SYSPLL_STS        0x114
>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL0        0x140
>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL1        0x144
>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL2        0x148
>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL3        0x14c
>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL4        0x150
>>>>>>>> +#define ANACTRL_HIFIPLL_STS        0x154
>>>>>>>> +#define ANACTRL_AUDDDS_CTRL0        0x180
>>>>>>>> +#define ANACTRL_AUDDDS_CTRL1        0x184
>>>>>>>> +#define ANACTRL_AUDDDS_CTRL2        0x188
>>>>>>>> +#define ANACTRL_AUDDDS_CTRL3        0x18c
>>>>>>>> +#define ANACTRL_AUDDDS_CTRL4        0x190
>>>>>>>> +#define ANACTRL_AUDDDS_STS        0x194
>>>>>>>> +#define ANACTRL_MISCTOP_CTRL0        0x1c0
>>>>>>>> +#define ANACTRL_POR_CNTL        0x208
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * CLKID index values
>>>>>>>> + *
>>>>>>>> + * These indices are entirely contrived and do not map onto the
>>>>>>>> hardware.
>>>>>>>> + * It has now been decided to expose everything by default in the
>>>>>>>> DT header:
>>>>>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we
>>>>>>>> don't want
>>>>>>>> + * to expose, such as the internal muxes and dividers of composite
>>>>>>>> clocks,
>>>>>>>> + * will remain defined here.
>>>>>>>> + */
>>>>>>>> +#define CLKID_FIXED_PLL_DCO        0
>>>>>>>> +#define CLKID_FCLK_DIV2_DIV        2
>>>>>>>> +#define CLKID_FCLK_DIV3_DIV        3
>>>>>>>> +#define CLKID_FCLK_DIV5_DIV        4
>>>>>>>> +#define CLKID_FCLK_DIV7_DIV        5
>>>>>>>> +#define NR_PLL_CLKS            11
>>>>>>>> +
>>>>>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>>>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>>>>>> +
>>>>>>>> +#endif /* __A1_PLL_H */
>>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..86a4733
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>>> @@ -0,0 +1,2264 @@
>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>> +#include "clk-pll.h"
>>>>>>>> +#include "clk-dualdiv.h"
>>>>>>>> +#include "meson-eeclk.h"
>>>>>>>> +#include "a1.h"
>>>>>>>
>>>>>>> Same as above
>>>>>> OK, I will change the order.
>>>>>> In fact, the clk-pll.h is not used in the current driver.
>>>>>> I will remove it.
>>>>>>>
>>>>>>>> +
>>>>>>>> +/* PLLs clock in gates, its parent is xtal */
>>>>>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>>> +        .bit_idx = 0,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "xtal_clktree",
>>>>>>>> +        .ops = &clk_regmap_gate_ro_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>> +            .fw_name = "xtal",
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * switch for xtal clock
>>>>>>>> +         * Linux should not change it at runtime
>>>>>>>> +         */
>>>>>>>
>>>>>>> Comment not useful: it uses the Ro ops
>>>>>>>
>>>>>> OK,  remove the comments
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>>> +        .bit_idx = 1,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "xtal_fixpll",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>> +            .fw_name = "xtal",
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +        /*
>>>>>>>> +         * it feeds DDR,AXI,APB bus
>>>>>>>> +         * Linux should not change it at runtime
>>>>>>>> +         */
>>>>>>>
>>>>>>> Again, the child are critical, not directly this clock from your
>>>>>>> comment.
>>>>>>>
>>>>>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>>>>>
>>>>>> repace as clk_regmap_gate_ro_ops
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>
>>>>>> [ ... ]
>>>>>>
>>>>>>>> +
>>>>>>>> +/* dsp a clk */
>>>>>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>>>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>> +    { .fw_name = "fclk_div2", },
>>>>>>>> +    { .fw_name = "fclk_div3", },
>>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>>> +    { .fw_name = "hifi_pll", },
>>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .mask = 0x7,
>>>>>>>> +        .shift = 10,
>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspa_a_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>
>>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>> Yes, I miss the flag.
>>>>>>>
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 10,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspa_a_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_a_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_a = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .bit_idx = 13,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspa_a",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_a_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .mask = 0x7,
>>>>>>>> +        .shift = 26,
>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspa_b_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>
>>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>>>
>>>>>> Yes, I will add it.
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .shift = 16,
>>>>>>>> +        .width = 10,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspa_b_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_b_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_b = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .bit_idx = 29,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspa_b",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_b_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 15,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspa_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>> +            { .hw = &a1_dspa_a.hw },
>>>>>>>> +            { .hw = &a1_dspa_b.hw },
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 2,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>>> +        .bit_idx = 1,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspa_en_dspa",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>
>>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>>
>>>>>> I should remove it
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>>> +        .bit_idx = 0,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspa_en_nic",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspa_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>
>>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>>
>>>>>> I should remove it
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>
>>>>>>> Same question and remarks applies to DSP B
>>>>>>>
>>>>>> got it
>>>>>>>> +/* dsp b clk */
>>>>>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .mask = 0x7,
>>>>>>>> +        .shift = 10,
>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspb_a_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 10,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspb_a_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_a_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_a = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .bit_idx = 13,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspb_a",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_a_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .mask = 0x7,
>>>>>>>> +        .shift = 26,
>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspb_b_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .shift = 16,
>>>>>>>> +        .width = 10,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspb_b_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_b_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_b = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .bit_idx = 29,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspb_b",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_b_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 15,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dspb_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_a.hw, &a1_dspb_b.hw,
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 2,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>>> +        .bit_idx = 1,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspb_en_dspb",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>>> +        .bit_idx = 0,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dspb_en_nic",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dspb_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* 12M/24M clock */
>>>>>>>> +static struct clk_regmap a1_24m = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = CLK12_24_CTRL,
>>>>>>>> +        .bit_idx = 11,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "24m",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>> +            .fw_name = "xtal",
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>
>>>>>> [ ... ]
>>>>>>
>>>>>>>> +static struct clk_regmap a1_saradc_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 9,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "saradc_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>> +            { .fw_name = "xtal", },
>>>>>>>> +            { .hw = &a1_sys_clk.hw, },
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 2,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_saradc_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "saradc_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_saradc_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_saradc_clk = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>> +        .bit_idx = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "saradc_clk",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_saradc_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm a/b/c/d parent data */
>>>>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>>> +};
>>>>>>>
>>>>>>> Looks like the same as SAR ADC
>>>>>>>
>>>>>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>>>>>> +
>>>>>>>> +/* pwm a clk */
>>>>>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 9,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_a_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_a_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_a_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_a = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .bit_idx = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_a",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_a_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * The CPU working voltage is controlled by pwm_a
>>>>>>>> +         * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>>>>>> +         * to avoid changing at runtime.
>>>>>>>                                        ^ it
>>>>>>>
>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>                       "blabla. And" is strange
>>>>>>>
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>
>>>>>>> This only skips the late_init() disable of unused clocks
>>>>>>>
>>>>>>> Be aware that this is not fool-proof. If at any time a driver enable
>>>>>>> then disable the clock, the clock will be disable and I guess your
>>>>>>> platform will die if this provides the CPU voltage.
>>>>>> OK, CLK_IS_CRITICAL is better.
>>>>>>>
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm b clk */
>>>>>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 25,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_b_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .shift = 16,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_b_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_b_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_b = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>> +        .bit_idx = 24,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_b",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_b_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm c clk */
>>>>>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 9,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_c_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_c_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_c_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_c = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .bit_idx = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_c",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_c_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm d clk */
>>>>>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 25,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_d_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .shift = 16,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_d_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_d_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_d = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>> +        .bit_idx = 24,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_d",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_d_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm e clk */
>>>>>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .mask = 0x3,
>>>>>>>> +        .shift = 9,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_e_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_e_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_e_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_e = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .bit_idx = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_e",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_e_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* pwm f clk */
>>>>>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .mask = 0x3,
>>>>>>>> +        .shift = 25,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_f_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .shift = 16,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "pwm_f_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_f_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_pwm_f = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>> +        .bit_idx = 24,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "pwm_f",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_pwm_f_div.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>
>>>>>> [ ... ]
>>>>>>
>>>>>>>> +
>>>>>>>> +/* dmc clk */
>>>>>>>> +static struct clk_regmap a1_dmc_sel = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>> +        .mask = 0x3,
>>>>>>>> +        .shift = 9,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dmc_sel",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = sd_emmc_parents,
>>>>>>>> +        .num_parents = 4,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dmc_div = {
>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>> +        .shift = 0,
>>>>>>>> +        .width = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dmc_div",
>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dmc_sel.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>> +        .mask = 0x1,
>>>>>>>> +        .shift = 15,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "dmc_sel2",
>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>> +            { .hw = &a1_dmc_div.hw },
>>>>>>>> +            { .fw_name = "xtal", },
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 2,
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct clk_regmap a1_dmc = {
>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>> +        .bit_idx = 8,
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>> +        .name = "dmc",
>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_dmc_sel2.hw
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        /*
>>>>>>>> +         * This clock is used by DDR clock which setted in BL2
>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>> clock to
>>>>>>>> +         * be marked as critical:
>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>> possible
>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>> the
>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>
>>>>>>> Should you put all this DMC stuff in RO until you got a driver for
>>>>>>> it ?
>>>>>> OK, replace as clk_regmap_gate_ro_ops
>>>>>>>
>>>>>> [ ... ]
>>>>>>>> +
>>>>>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> +    int ret;
>>>>>>>> +
>>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>>> +    if (ret)
>>>>>>>> +        return ret;
>>>>>>>> +
>>>>>>>> +    return 0;
>>>>>>>> +}
>>>>>>>
>>>>>>> Again this function is function is useless and it makes me wonder if
>>>>>>> you
>>>>>>> should really be using meson_eeclkc_probe()
>>>>>>>
>>>>>>> This makes you use syscon which is not correct unless you have a good
>>>>>>> reason ?
>>>>>>>
>>>>>> If it can not use the meson_eeclkc_probe(), I will realize a probe
>>>>>> function
>>>>>> which is mostly duplicate with meson_eeclkc_probe() except
>>>>>> "syscon_node_to_regmap"
>>>>>>
>>>>>> Maybe another common probe function and a new file are required for A1
>>>>>> three drivers? (include the CPU clock driver)
>>>>>
>>>>> Maybe
>>>>>
>>>> I will add a new function base on meson-eeclk.c
>>>>>>
>>>>>> Or using meson_eeclkc_probe is more easier?
>>>>>
>>>>> It is not question of easiness, but correctness.
>>>>>
>>>>>>
>>>>>>> Is there anything but clocks and resets in these register region ?
>>>>>> No, there is only clocks in the register region.
>>>>>> the same does the PLL register region.
>>>>>
>>>>> Then there is no reason to use syscon for those drivers
>>>>> Add a new probe function for A1
>>>>>>>
>>>>>>>> +
>>>>>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>>>>>> +        .regmap_clks = a1_periphs_regmaps,
>>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>>>>>> +        .hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>>>>>> +};
>>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>>> +    {
>>>>>>>> +        .compatible = "amlogic,a1-periphs-clkc",
>>>>>>>> +        .data = &a1_periphs_data
>>>>>>>> +    },
>>>>>>>> +    { /* sentinel */ }
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>>> +    .probe        = meson_a1_periphs_probe,
>>>>>>>> +    .driver        = {
>>>>>>>> +        .name    = "a1-periphs-clkc",
>>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..1ae5e04
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/clk/meson/a1.h
>>>>>>>> @@ -0,0 +1,120 @@
>>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#ifndef __A1_H
>>>>>>>> +#define __A1_H
>>>>>>>> +
>>>>>>>> +/* peripheral clock controller register offset */
>>>>>>>> +#define SYS_OSCIN_CTRL            0x0
>>>>>>>> +#define RTC_BY_OSCIN_CTRL0        0x4
>>>>>>>> +#define RTC_BY_OSCIN_CTRL1        0x8
>>>>>>>> +#define RTC_CTRL            0xc
>>>>>>>> +#define SYS_CLK_CTRL0            0x10
>>>>>>>> +#define AXI_CLK_CTRL0            0x14
>>>>>>>> +#define SYS_CLK_EN0            0x1c
>>>>>>>> +#define SYS_CLK_EN1            0x20
>>>>>>>> +#define AXI_CLK_EN            0x24
>>>>>>>> +#define DSPA_CLK_EN            0x28
>>>>>>>> +#define DSPB_CLK_EN            0x2c
>>>>>>>> +#define DSPA_CLK_CTRL0            0x30
>>>>>>>> +#define DSPB_CLK_CTRL0            0x34
>>>>>>>> +#define CLK12_24_CTRL            0x38
>>>>>>>> +#define GEN_CLK_CTRL            0x3c
>>>>>>>> +#define TIMESTAMP_CTRL0            0x40
>>>>>>>> +#define TIMESTAMP_CTRL1            0x44
>>>>>>>> +#define TIMESTAMP_CTRL2            0x48
>>>>>>>> +#define TIMESTAMP_VAL0            0x4c
>>>>>>>> +#define TIMESTAMP_VAL1            0x50
>>>>>>>> +#define TIMEBASE_CTRL0            0x54
>>>>>>>> +#define TIMEBASE_CTRL1            0x58
>>>>>>>> +#define SAR_ADC_CLK_CTRL        0xc0
>>>>>>>> +#define PWM_CLK_AB_CTRL            0xc4
>>>>>>>> +#define PWM_CLK_CD_CTRL            0xc8
>>>>>>>> +#define PWM_CLK_EF_CTRL            0xcc
>>>>>>>> +#define SPICC_CLK_CTRL            0xd0
>>>>>>>> +#define TS_CLK_CTRL            0xd4
>>>>>>>> +#define SPIFC_CLK_CTRL            0xd8
>>>>>>>> +#define USB_BUSCLK_CTRL            0xdc
>>>>>>>> +#define SD_EMMC_CLK_CTRL        0xe0
>>>>>>>> +#define CECA_CLK_CTRL0            0xe4
>>>>>>>> +#define CECA_CLK_CTRL1            0xe8
>>>>>>>> +#define CECB_CLK_CTRL0            0xec
>>>>>>>> +#define CECB_CLK_CTRL1            0xf0
>>>>>>>> +#define PSRAM_CLK_CTRL            0xf4
>>>>>>>> +#define DMC_CLK_CTRL            0xf8
>>>>>>>> +#define FCLK_DIV1_SEL            0xfc
>>>>>>>> +#define TST_CTRL            0x100
>>>>>>>> +
>>>>>>>> +#define CLKID_XTAL_CLKTREE        0
>>>>>>>> +#define CLKID_SYS_A_SEL            89
>>>>>>>> +#define CLKID_SYS_A_DIV            90
>>>>>>>> +#define CLKID_SYS_A            91
>>>>>>>> +#define CLKID_SYS_B_SEL            92
>>>>>>>> +#define CLKID_SYS_B_DIV            93
>>>>>>>> +#define CLKID_SYS_B            94
>>>>>>>> +#define CLKID_DSPA_A_SEL        95
>>>>>>>> +#define CLKID_DSPA_A_DIV        96
>>>>>>>> +#define CLKID_DSPA_A            97
>>>>>>>> +#define CLKID_DSPA_B_SEL        98
>>>>>>>> +#define CLKID_DSPA_B_DIV        99
>>>>>>>> +#define CLKID_DSPA_B            100
>>>>>>>> +#define CLKID_DSPB_A_SEL        101
>>>>>>>> +#define CLKID_DSPB_A_DIV        102
>>>>>>>> +#define CLKID_DSPB_A            103
>>>>>>>> +#define CLKID_DSPB_B_SEL        104
>>>>>>>> +#define CLKID_DSPB_B_DIV        105
>>>>>>>> +#define CLKID_DSPB_B            106
>>>>>>>> +#define CLKID_RTC_32K_CLKIN        107
>>>>>>>> +#define CLKID_RTC_32K_DIV        108
>>>>>>>> +#define CLKID_RTC_32K_XTAL        109
>>>>>>>> +#define CLKID_RTC_32K_SEL        110
>>>>>>>> +#define CLKID_CECB_32K_CLKIN        111
>>>>>>>> +#define CLKID_CECB_32K_DIV        112
>>>>>>>> +#define CLKID_CECB_32K_SEL_PRE        113
>>>>>>>> +#define CLKID_CECB_32K_SEL        114
>>>>>>>> +#define CLKID_CECA_32K_CLKIN        115
>>>>>>>> +#define CLKID_CECA_32K_DIV        116
>>>>>>>> +#define CLKID_CECA_32K_SEL_PRE        117
>>>>>>>> +#define CLKID_CECA_32K_SEL        118
>>>>>>>> +#define CLKID_DIV2_PRE            119
>>>>>>>> +#define CLKID_24M_DIV2            120
>>>>>>>> +#define CLKID_GEN_SEL            121
>>>>>>>> +#define CLKID_GEN_DIV            122
>>>>>>>> +#define CLKID_SARADC_DIV        123
>>>>>>>> +#define CLKID_PWM_A_SEL            124
>>>>>>>> +#define CLKID_PWM_A_DIV            125
>>>>>>>> +#define CLKID_PWM_B_SEL            126
>>>>>>>> +#define CLKID_PWM_B_DIV            127
>>>>>>>> +#define CLKID_PWM_C_SEL            128
>>>>>>>> +#define CLKID_PWM_C_DIV            129
>>>>>>>> +#define CLKID_PWM_D_SEL            130
>>>>>>>> +#define CLKID_PWM_D_DIV            131
>>>>>>>> +#define CLKID_PWM_E_SEL            132
>>>>>>>> +#define CLKID_PWM_E_DIV            133
>>>>>>>> +#define CLKID_PWM_F_SEL            134
>>>>>>>> +#define CLKID_PWM_F_DIV            135
>>>>>>>> +#define CLKID_SPICC_SEL            136
>>>>>>>> +#define CLKID_SPICC_DIV            137
>>>>>>>> +#define CLKID_SPICC_SEL2        138
>>>>>>>> +#define CLKID_TS_DIV            139
>>>>>>>> +#define CLKID_SPIFC_SEL            140
>>>>>>>> +#define CLKID_SPIFC_DIV            141
>>>>>>>> +#define CLKID_SPIFC_SEL2        142
>>>>>>>> +#define CLKID_USB_BUS_SEL        143
>>>>>>>> +#define CLKID_USB_BUS_DIV        144
>>>>>>>> +#define CLKID_SD_EMMC_SEL        145
>>>>>>>> +#define CLKID_SD_EMMC_DIV        146
>>>>>>>> +#define CLKID_SD_EMMC_SEL2        147
>>>>>>>> +#define CLKID_PSRAM_SEL            148
>>>>>>>> +#define CLKID_PSRAM_DIV            149
>>>>>>>> +#define CLKID_PSRAM_SEL2        150
>>>>>>>> +#define CLKID_DMC_SEL            151
>>>>>>>> +#define CLKID_DMC_DIV            152
>>>>>>>> +#define CLKID_DMC_SEL2            153
>>>>>>>> +#define NR_CLKS                154
>>>>>>>> +
>>>>>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>>>>>> +
>>>>>>>> +#endif /* __A1_H */
>>>>>>>
>>>>>>> .
>>>>>>>
>>>>>
>>>>> .
>>>>>
>>>
>>> .
>>>


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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-20 15:35                 ` Jerome Brunet
@ 2019-11-21  3:21                   ` Jian Hu
  2019-11-25 10:14                     ` Jerome Brunet
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-21  3:21 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel

Hi, Jerome

On 2019/11/20 23:35, Jerome Brunet wrote:
> 
> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, jerome
>>
>> Is there any problem about fixed_pll_dco's parent_data?
>>
>> Now both name and fw_name are described in parent_data.
> 
> Yes, there is a problem.  This approach is incorrect, as I've tried to
> explain a couple times already. Let me try to re-summarize why this
> approach is incorrect.
> 
> Both fw_name and name should be provided when it is possible that
> the DT does not describe the input clock. IOW, it is only for controllers
> which relied on the global name so far and are now starting to describe
> the clock input in DT
> 
> This is not your case.
> Your controller is new and DT will have the correct
> info
> 
> You are trying work around an ordering issue by providing both fw_name
> and name. This is not correct and I'll continue to nack it.
> 
> If the orphan clock is not reparented as you would expect, I suggest you
> try to look a bit further at how the reparenting of orphans is done in
> CCF and why it does not match your expectation.
> 
I have debugged the handle for orphan clock in CCF, Maybe you are 
missing the last email.
Even though the clock index exit, it will get failed for the orphan 
clock's parent clock due to it has not beed added to the provider.

List it again:
---
#1 add DT describtion
    add fw_name alone


DT description:

clkc_pll: pll-clock-controller {
          compatible = "amlogic,a1-pll-clkc";
          #clock-cells = <1>;
          reg = <0 0x7c80 0 0x21c>;
          clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
                <&clkc_periphs CLKID_XTAL_HIFIPLL>;
          clock-names = "xtal_fixpll", "xtal_hifipll";
  };

  clkc_periphs: periphs-clock-controller {
          compatible = "amlogic,a1-periphs-clkc";
          #clock-cells = <1>;
          reg = <0 0x800 0 0x104>;
          clocks = <&clkc_pll CLKID_FCLK_DIV2>,
                   <&clkc_pll CLKID_FCLK_DIV3>,
                   <&clkc_pll CLKID_FCLK_DIV5>,
                   <&clkc_pll CLKID_FCLK_DIV7>,
                   <&clkc_pll CLKID_HIFI_PLL>,
                   <&xtal>;
          clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
                        "fclk_div7", "hifi_pll", "xtal";
  };

And PLL clock driver probe first, periphs clock driver probe after the 
PLL driver.

When register xtal_fixpll clock in periphs driver, it will walk the list 
of orphan clocks, it will try to get the orphan's parent.

in drivers/clk/clk/c +3364

	hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
		struct clk_core *parent = __clk_init_parent(orphan);
                 ...
              }

  the code path is :

  struct clk_core *parent = __clk_init_parent(orphan)

      -> clk_core_get_parent_by_index(core, index)

       ->clk_core_fill_parent_index

        ->clk_core_get

         ->hw = of_clk_get_hw_from_clkspec

the root case is of_clk_get_hw_from_clkspec, Now fixed_dco_pll clock is

a orphan clock, its parent clock is xtal_fixpll. Add it is defined in DT.

The "xtal_fixpll" clock is in periphs provider, but the periphs provider 
has not been registered to the kernel, it return a wrong hw clock when 
of_clk_get_hw_from_clkspec is executed. In a word, the orphan clock's 
parent clock can not be found.


  In of_clk_get_hw_from_clkspec function, it will get hw_clk from
  clk_provider, However the peripheral clock provider has not been
  added to "of_clk_providers" LIST, In other words, the peripheral clock
  provider does not exist at this time. (devm_of_clk_add_hw_provider has
  not run)

  So It will get parent failed from DT.

  even if name is added in parent_data, PTR_ERR(parent) is not equal
  -ENOENT, it will not run clk_core_lookup, the fixed_pll_dco is still a
  orphan clock.

  #2 Not add DT describtion

  the code path is :

  struct clk_core *parent = __clk_init_parent(orphan)

      -> clk_core_get_parent_by_index(core, index)

       ->clk_core_fill_parent_index

        ->clk_core_get

         ->clk_find_hw

  clk_find_hw is used when the clock is registered by clk_register_clkdev

  So it wlll get parented failed by clk_find_hw.

  When name is described in parent_data, the parent will be found by

  clk_core_lookup.


  In this scene,Only fw_name in parent_data, the orphan clock's parent 
can not be found, But add the legacy name, the parent will be found.

  #3
  When the provider has not been added to the CCF, And fw_name is alone in
  parent_data in a orphan clock , How to get the orphan clock'parent ?
  It seems not supported.
---

>>
>> More debug message is in the last email.
>>
>> On 2019/11/13 22:21, Jian Hu wrote:
>>>
>>> On 2019/11/13 0:59, Jerome Brunet wrote:
>>>>
>>>> On Sat 09 Nov 2019 at 12:16, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> Hi, Jerome
>>>>>
>>>>> Sorry for late rely
>>>>>
>>>>> On 2019/11/4 16:24, Jerome Brunet wrote:
>>>>>>
>>>>>> On Fri 25 Oct 2019 at 13:32, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>
>>>>>>> Hi, Jerome
>>>>>>>
>>>>>>> Thanks for your review
>>>>>>>
>>>>>>> On 2019/10/21 19:41, Jerome Brunet wrote:
>>>>>>>>
>>>>>>>> On Fri 18 Oct 2019 at 09:14, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>>>
>>>>>>>>> The Amlogic A1 clock includes three drivers:
>>>>>>>>> peripheral clocks, pll clocks, CPU clocks.
>>>>>>>>> sys pll and CPU clocks will be sent in next patch.
>>>>>>>>>
>>>>>>>>> Unlike the previous series, there is no EE/AO domain
>>>>>>>>> in A1 CLK controllers.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>>>>>>>> ---
>>>>>>>>>      drivers/clk/meson/Kconfig  |   10 +
>>>>>>>>>      drivers/clk/meson/Makefile |    1 +
>>>>>>>>>      drivers/clk/meson/a1-pll.c |  345 +++++++
>>>>>>>>>      drivers/clk/meson/a1-pll.h |   56 ++
>>>>>>>>>      drivers/clk/meson/a1.c     | 2264
>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>      drivers/clk/meson/a1.h     |  120 +++
>>>>>>>>>      6 files changed, 2796 insertions(+)
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1-pll.c
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1-pll.h
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1.c
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1.h
>>>>>>>>
>>>>>>>> In the next version, one
>>>>>>> OK, I will send a1 peripheral and pll driver in two patch.
>>>>>>>>
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>>>>>>> index dabeb43..c2809b2 100644
>>>>>>>>> --- a/drivers/clk/meson/Kconfig
>>>>>>>>> +++ b/drivers/clk/meson/Kconfig
>>>>>>>>> @@ -93,6 +93,16 @@ config COMMON_CLK_AXG_AUDIO
>>>>>>>>>            Support for the audio clock controller on AmLogic A113D
>>>>>>>>> devices,
>>>>>>>>>            aka axg, Say Y if you want audio subsystem to work.
>>>>>>>>>      +config COMMON_CLK_A1
>>>>>>>>> +    bool
>>>>>>>>> +    depends on ARCH_MESON
>>>>>>>>> +    select COMMON_CLK_MESON_REGMAP
>>>>>>>>> +    select COMMON_CLK_MESON_DUALDIV
>>>>>>>>> +    select COMMON_CLK_MESON_PLL
>>>>>>>>> +    help
>>>>>>>>> +      Support for the clock controller on Amlogic A113L device,
>>>>>>>>> +      aka a1. Say Y if you want peripherals to work.
>>>>>>>>> +
>>>>>>>>>      config COMMON_CLK_G12A
>>>>>>>>>          bool
>>>>>>>>>          depends on ARCH_MESON
>>>>>>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>>>>>>> index 3939f21..28cbae1 100644
>>>>>>>>> --- a/drivers/clk/meson/Makefile
>>>>>>>>> +++ b/drivers/clk/meson/Makefile
>>>>>>>>> @@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) +=
>>>>>>>>> vid-pll-div.o
>>>>>>>>>        obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>>>>>>>      obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>>>>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1-pll.o a1.o
>>>>>>>>
>>>>>>>> So far, all the controller had there own option, I don't see why it
>>>>>>>> should be different here.
>>>>>>>>
>>>>>>> OK, I will add the other option CONFIG_COMMON_CLK_A1_PLL for pll
>>>>>>> driver
>>>>>>>>>      obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>>>>>>>      obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>>>>>>>>>      obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
>>>>>>>>> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..486d964
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/clk/meson/a1-pll.c
>>>>>>>>> @@ -0,0 +1,345 @@
>>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>>
>>>>>>>> Hum ... looks like some things are missing here
>>>>>>>>
>>>>>>>> #include <linux/of_device.h>
>>>>>>>> #include <linux/clk-provider.h>
>>>>>>>>
>>>>>>>> ?
>>>>>>> #1
>>>>>>> There is <linux/clk-provider.h> in meson-eeclk.h file,
>>>>>>>
>>>>>>> and for A1 driver(a1.c/a1-pll.c) the head file is not requied.
>>>>>>>
>>>>>>> #2
>>>>>>> For A1 driver, the file "linux/of_device.h" is not required.
>>>>>>> It is required by meson-eeclk.c in fact.
>>>>>>
>>>>>> You are using what is provided by these headers directly in this file
>>>>>> If meson-eeclk ever changes, your driver breaks
>>>>>>
>>>>> OK, I will add the two header file.
>>>>>>>>
>>>>>>>>> +#include "clk-pll.h"
>>>>>>>>> +#include "meson-eeclk.h"
>>>>>>>>> +#include "a1-pll.h"
>>>>>>>>
>>>>>>>> Alphanumeric order please
>>>>>>>>
>>>>>>> OK, I will change it in the next version.
>>>>>>>
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fixed_pll_dco = {
>>>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>>>> +        .en = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +            .shift   = 28,
>>>>>>>>> +            .width   = 1,
>>>>>>>>> +        },
>>>>>>>>> +        .m = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +            .shift   = 0,
>>>>>>>>> +            .width   = 8,
>>>>>>>>> +        },
>>>>>>>>> +        .n = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +            .shift   = 10,
>>>>>>>>> +            .width   = 5,
>>>>>>>>> +        },
>>>>>>>>> +        .frac = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL1,
>>>>>>>>> +            .shift   = 0,
>>>>>>>>> +            .width   = 19,
>>>>>>>>> +        },
>>>>>>>>> +        .l = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +            .shift   = 31,
>>>>>>>>> +            .width   = 1,
>>>>>>>>> +        },
>>>>>>>>> +        .rst = {
>>>>>>>>> +            .reg_off = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +            .shift   = 29,
>>>>>>>>> +            .width   = 1,
>>>>>>>>> +        },
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fixed_pll_dco",
>>>>>>>>> +        .ops = &meson_clk_pll_ro_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>>>> +            .name = "xtal_fixpll",
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fixed_pll = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +        .bit_idx = 20,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "fixed_pll",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fixed_pll_dco.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * This clock is fclk_div2/3/4's parent,
>>>>>>>>> +         * However, fclk_div2/3/5 feeds AXI/APB/DDR.
>>>>>>>>
>>>>>>>> is it fclk_div2/3/4 or fclk_div2/3/5 ?
>>>>>>>>
>>>>>>>>> +         * It is required by the platform to operate correctly.
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>
>>>>>>>> Don't blindly copy/paste comments from other drivers. There is no
>>>>>>>> driver
>>>>>>>> for the devices you are mentionning so the end of the comment is
>>>>>>>> confusing. The 3 first lines were enough
>>>>>>>>
>>>>>>> OK, I will remove the confusing comments
>>>>>>>
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>
>>>>>>>> >From your comment, I understand that some child are critical, not
>>>>>>>> this
>>>>>>>> particular (or at least, not directly). So this can be removed AFAICT
>>>>>>>>
>>>>>>>> You should even need CLK_IGNORE_UNUSED for this one since the clock
>>>>>>>> will
>>>>>>>> already be enabled before the late_init() kicks in
>>>>>>>>
>>>>>>> OK, I will replace it as CLK_IGNORE_UNUSED.
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const struct pll_mult_range a1_hifi_pll_mult_range = {
>>>>>>>>> +    .min = 32,
>>>>>>>>> +    .max = 64,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const struct reg_sequence a1_hifi_init_regs[] = {
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us =
>>>>>>>>> 10 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us =
>>>>>>>>> 40 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_hifi_pll = {
>>>>>>>>> +    .data = &(struct meson_clk_pll_data){
>>>>>>>>> +        .en = {
>>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>>> +            .shift   = 28,
>>>>>>>>> +            .width   = 1,
>>>>>>>>> +        },
>>>>>>>>> +        .m = {
>>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>>> +            .shift   = 0,
>>>>>>>>> +            .width   = 8,
>>>>>>>>> +        },
>>>>>>>>> +        .n = {
>>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>>>>>>> +            .shift   = 10,
>>>>>>>>> +            .width   = 5,
>>>>>>>>> +        },
>>>>>>>>> +        .frac = {
>>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>>>>>>> +            .shift   = 0,
>>>>>>>>> +            .width   = 19,
>>>>>>>>> +        },
>>>>>>>>> +        .l = {
>>>>>>>>> +            .reg_off = ANACTRL_HIFIPLL_STS,
>>>>>>>>> +            .shift   = 31,
>>>>>>>>> +            .width   = 1,
>>>>>>>>> +        },
>>>>>>>>> +        .range = &a1_hifi_pll_mult_range,
>>>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>>>> +        .strict_sequence = true,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "hifi_pll",
>>>>>>>>> +        .ops = &meson_clk_pll_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data){
>>>>>>>>> +            .fw_name = "xtal_fixpll",
>>>>>>>>> +            .name = "xtal_fixpll",
>>>>>>>>
>>>>>>>> Both should provided when a controller transition from the old way of
>>>>>>>> describing parent to the new way. This is a new controller so it does
>>>>>>>> not apply.
>>>>>>> I do not understand why it does not apply, could you explain more?
>>>>>>
>>>>>> Your driver is new, it is not something old transitioning from global
>>>>>> name to clock in DT !
>>>>>>
>>>>>>>
>>>>>>> The xtal_fixpll clock is registered in another peripheral driver, If
>>>>>>> do not
>>>>>>> desribe the "name" member in parent_data, "fw_name" does not work
>>>>>>> because
>>>>>>> it has not been registered. the hifi_pll parent will be null in
>>>>>>> /sys/kernel/debug/clk/hifi_pll/clk_parent.
>>>>>>>
>>>>>>> HIFI PLL will be a orphan clock, but its parent should be xtal_fixpll.
>>>>>>
>>>>>> There will be an orphan yes, temporarily, until both controllers are
>>>>>> up.
>>>>>> Once both controller are up, the clock will be reparented if necessary.
>>>>>>
>>>>>>>
>>>>>>> So both of "fw_name" of "name" should be described.
>>>>>>
>>>>>> No
>>>>>>
>>>>>
>>>>> #1
>>>>>
>>>>> Here, I am still confused.
>>>>>   From the point of view of the phenomenon, the name in parent_data is
>>>>> required.
>>>>>
>>>>>
>>>>> HIFI PLL is described like this:
>>>>>
>>>>>      .parent_data = &(const struct clk_parent_data){
>>>>>          .fw_name = "xtal_hifipll",
>>>>>          .name = "xtal_hifipll"
>>>>>      }
>>>>>
>>>>> Fixed PLL is described like this:
>>>>>
>>>>>      .parent_data = &(const struct clk_parent_data){
>>>>>          .fw_name = "xtal_fixpll",
>>>>>      },
>>>>>
>>>>> After the system boot completely, run cat
>>>>> /sys/kernel/debug/clk/clk_summary, Here is the result:
>>>>>
>>>>> # cat /sys/kernel/debug/clk/clk_summary
>>>>>                    enable  prepare  protect                    duty
>>>>>      clock         count   count    count  rate accuracy phase cycle
>>>>> --------------------------------------------------------------------
>>>>>    xtal            5        5        0    24000000    0     0  50000
>>>>>       ts_div       0        0        0    24000000    0     0  50000
>>>>>          ts        0        0        0    24000000    0     0  50000
>>>>>       pwm_f_sel    0        0        0    24000000    0     0  50000
>>>>>          pwm_f_div 0        0        0    24000000    0     0  50000
>>>>>             pwm_f  0        0        0    24000000    0     0  50000
>>>>> ......
>>>>>       xtal_syspll  0        0        0    24000000    0     0  50000
>>>>>       xtal_hifipll 0        0        0    24000000    0     0  50000
>>>>>          hifi_pll  0        0        0  1536000000    0     0  50000
>>>>>       xtal_usb_ctrl 0        0        0    24000000   0     0  50000
>>>>>       xtal_usb_phy  0        0        0    24000000   0     0  50000
>>>>>       xtal_fixpll   0        0        0    24000000   0     0  50000
>>>>>       xtal_clktree  0        0        0    24000000   0     0  50000
>>>>>    fixed_pll_dco    1        1        0         0   0     0  50000
>>>>
>>>> This means that CCF what not able to resolve the parent.
>>>> Either:
>>>> * you've made a mistake somewhere
>>>> * There is bug in CCF when the parent device is not available at probe
>>>> time, the clock is not properly reparented
>>>>
>>>
>>> #1 Add DT describtion
>>>
>>> DT description:
>>>
>>> clkc_pll: pll-clock-controller {
>>>         compatible = "amlogic,a1-pll-clkc";
>>>         #clock-cells = <1>;
>>>         reg = <0 0x7c80 0 0x21c>;
>>>         clocks = <&clkc_periphs CLKID_XTAL_FIXPLL>,
>>>               <&clkc_periphs CLKID_XTAL_HIFIPLL>;
>>>         clock-names = "xtal_fixpll", "xtal_hifipll";
>>> };
>>>
>>> clkc_periphs: periphs-clock-controller {
>>>         compatible = "amlogic,a1-periphs-clkc";
>>>         #clock-cells = <1>;
>>>         reg = <0 0x800 0 0x104>;
>>>         clocks = <&clkc_pll CLKID_FCLK_DIV2>,
>>>                  <&clkc_pll CLKID_FCLK_DIV3>,
>>>                  <&clkc_pll CLKID_FCLK_DIV5>,
>>>                  <&clkc_pll CLKID_FCLK_DIV7>,
>>>                  <&clkc_pll CLKID_HIFI_PLL>,
>>>                  <&xtal>;
>>>         clock-names = "fclk_div2", "fclk_div3", "fclk_div5",
>>>                       "fclk_div7", "hifi_pll", "xtal";
>>> };
>>>
>>> And PLL clock driver probe first.
>>>
>>> When register xtal_fixpll clock in periphs driver
>>>
>>> it will walk the list of orphan clocks, it will try to get the orphan
>>> parent.
>>>
>>> the code path is :
>>>
>>> struct clk_core *parent = __clk_init_parent(orphan)
>>>
>>>     -> clk_core_get_parent_by_index(core, index)
>>>
>>>      ->clk_core_fill_parent_index
>>>
>>>       ->clk_core_get
>>>
>>>        ->of_clk_get_hw_from_clkspec
>>>
>>> In of_clk_get_hw_from_clkspec function, it will get hw_clk from
>>> clk_provider, However the peripheral clock provider has not been
>>> added to "of_clk_providers" LIST, In other words, the peripheral clock
>>> provider does not exist at this time. (devm_of_clk_add_hw_provider has
>>> not run)
>>>
>>> So It will get parent failed from DT.
>>>
>>> even if name is added in parent_data, PTR_ERR(parent) is not equal
>>> -ENOENT, it will not run clk_core_lookup, the fixed_pll_dco is still a
>>> orphan clock.
>>>
>>> #2 Not add DT describtion
>>>
>>> the code path is :
>>>
>>> struct clk_core *parent = __clk_init_parent(orphan)
>>>
>>>     -> clk_core_get_parent_by_index(core, index)
>>>
>>>      ->clk_core_fill_parent_index
>>>
>>>       ->clk_core_get
>>>
>>>        ->clk_find_hw
>>>
>>> clk_find_hw is used when the clock is registered by clk_register_clkdev
>>>
>>> So it wlll get parented failed by clk_find_hw.
>>>
>>> When name is described in parent_data, the parent will be found by
>>>
>>> clk_core_lookup.
>>>
>>>
>>> In this scene,Only fw_name in parent_data, the orphan clock's parent can
>>> not be found, But add the legacy name, the parent will be found.
>>>
>>> #3
>>> When the provider has not been added to the CCF, And fw_name is alone in
>>> parent_data in a orphan clock , How to get the orphan clock'parent ?
>>> It seems not supported.
>>>
>>>> Either way, you'll have to debug a bit more
>>>>
>>>>>       fixed_pll     3        3        0         0   0     0  50000
>>>>>          fclk_div7_div 0     0        0         0   0     0  50000
>>>>> ....
>>>>>
>>>>> the hifi_pll's parent is xtal_hifi, And the hifi_pll default rate is
>>>>> right.
>>>>>
>>>>> but the fixed_pll_dco is a orphan clock, its parent is NULL.And its rate
>>>>> is zero.When the name in parent_data is added, its parent is
>>>>> xtal_fixpll.
>>>>>
>>>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_parent
>>>>> #
>>>>> # cat /sys/kernel/debug/clk/fixed_pll_dco/clk_rate
>>>>> 0
>>>>>
>>>>>
>>>>> #2
>>>>> In  ./drivers/clk/qcom/gcc-sm8150.c
>>>>> For some clocks, Both fw_name and name are described in parent_data
>>>>> struct.
>>>>
>>>> Those are being migrated to DT description which means that we don't
>>>> know if the DT will the correct description
>>>>
>>>> In this case the clock framework will first try DT and if DT does
>>>> provide this fw_name, it will fallback to the legacy name.
>>>>
>>>> This is not your case as this is a new platform for which we know the DT
>>>> name exist.
>>>>
>>> It will get parent failed from DT as the previous says.
>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> Same for the other occurences.
>>>>>>>>
>>>>>>>> Also, I think you meant xtal_hifipll
>>>>>>> Yes,I will correct it.
>>>>>>>>
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_fixed_factor a1_fclk_div2_div = {
>>>>>>>>> +    .mult = 1,
>>>>>>>>> +    .div = 2,
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div2_div",
>>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fclk_div2 = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +        .bit_idx = 21,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div2",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fclk_div2_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * This clock is used by DDR clock in BL2 firmware
>>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_fixed_factor a1_fclk_div3_div = {
>>>>>>>>> +    .mult = 1,
>>>>>>>>> +    .div = 3,
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div3_div",
>>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fclk_div3 = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +        .bit_idx = 22,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div3",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fclk_div3_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * This clock is used by APB bus which setted in Romcode
>>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_fixed_factor a1_fclk_div5_div = {
>>>>>>>>> +    .mult = 1,
>>>>>>>>> +    .div = 5,
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div5_div",
>>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fclk_div5 = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +        .bit_idx = 23,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div5",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fclk_div5_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * This clock is used by AXI bus which setted in Romcode
>>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_fixed_factor a1_fclk_div7_div = {
>>>>>>>>> +    .mult = 1,
>>>>>>>>> +    .div = 7,
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div7_div",
>>>>>>>>> +        .ops = &clk_fixed_factor_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fixed_pll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_fclk_div7 = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = ANACTRL_FIXPLL_CTRL0,
>>>>>>>>> +        .bit_idx = 24,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "fclk_div7",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_fclk_div7_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* Array of all clocks provided by this provider */
>>>>>>>>> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
>>>>>>>>> +    .hws = {
>>>>>>>>> +        [CLKID_FIXED_PLL_DCO]        = &a1_fixed_pll_dco.hw,
>>>>>>>>> +        [CLKID_FIXED_PLL]        = &a1_fixed_pll.hw,
>>>>>>>>> +        [CLKID_HIFI_PLL]        = &a1_hifi_pll.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV2]        = &a1_fclk_div2.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV3]        = &a1_fclk_div3.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV5]        = &a1_fclk_div5.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV7]        = &a1_fclk_div7.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV2_DIV]        = &a1_fclk_div2_div.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV3_DIV]        = &a1_fclk_div3_div.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV5_DIV]        = &a1_fclk_div5_div.hw,
>>>>>>>>> +        [CLKID_FCLK_DIV7_DIV]        = &a1_fclk_div7_div.hw,
>>>>>>>>> +        [NR_PLL_CLKS]            = NULL,
>>>>>>>>> +    },
>>>>>>>>> +    .num = NR_PLL_CLKS,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap *const a1_pll_regmaps[] = {
>>>>>>>>> +    &a1_fixed_pll_dco,
>>>>>>>>> +    &a1_fixed_pll,
>>>>>>>>> +    &a1_hifi_pll,
>>>>>>>>> +    &a1_fclk_div2,
>>>>>>>>> +    &a1_fclk_div3,
>>>>>>>>> +    &a1_fclk_div5,
>>>>>>>>> +    &a1_fclk_div7,
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static int meson_a1_pll_probe(struct platform_device *pdev)
>>>>>>>>> +{
>>>>>>>>> +    int ret;
>>>>>>>>> +
>>>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>>>> +    if (ret)
>>>>>>>>> +        return ret;
>>>>>>>>> +
>>>>>>>>> +    return 0;
>>>>>>>>> +}
>>>>>>>>
>>>>>>>> This function is useless.
>>>>>>>>
>>>>>>> OK, I will use meson_eeclkc_probe derectly.
>>>>>>>>> +
>>>>>>>>> +static const struct meson_eeclkc_data a1_pll_data = {
>>>>>>>>> +        .regmap_clks = a1_pll_regmaps,
>>>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_pll_regmaps),
>>>>>>>>> +        .hw_onecell_data = &a1_pll_hw_onecell_data,
>>>>>>>>> +};
>>>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>>>> +    {
>>>>>>>>> +        .compatible = "amlogic,a1-pll-clkc",
>>>>>>>>> +        .data = &a1_pll_data
>>>>>>>>> +    },
>>>>>>>>> +    { /* sentinel */ }
>>>>>>>>
>>>>>>>> Nitpick: don't need to write this, just write the line like this
>>>>>>>>
>>>>>>> OK, remove it.
>>>>>>>> ' }, {}'
>>>>>>>>
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>>>> +    .probe        = meson_a1_pll_probe,
>>>>>>>>> +    .driver        = {
>>>>>>>>> +        .name    = "a1-pll-clkc",
>>>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>>>> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..99ee2a9
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/clk/meson/a1-pll.h
>>>>>>>>> @@ -0,0 +1,56 @@
>>>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#ifndef __A1_PLL_H
>>>>>>>>> +#define __A1_PLL_H
>>>>>>>>> +
>>>>>>>>> +/* PLL register offset */
>>>>>>>>> +#define ANACTRL_FIXPLL_CTRL0        0x80
>>>>>>>>> +#define ANACTRL_FIXPLL_CTRL1        0x84
>>>>>>>>> +#define ANACTRL_FIXPLL_CTRL2        0x88
>>>>>>>>> +#define ANACTRL_FIXPLL_CTRL3        0x8c
>>>>>>>>> +#define ANACTRL_FIXPLL_CTRL4        0x90
>>>>>>>>> +#define ANACTRL_FIXPLL_STS        0x94
>>>>>>>>> +#define ANACTRL_SYSPLL_CTRL0        0x100
>>>>>>>>> +#define ANACTRL_SYSPLL_CTRL1        0x104
>>>>>>>>> +#define ANACTRL_SYSPLL_CTRL2        0x108
>>>>>>>>> +#define ANACTRL_SYSPLL_CTRL3        0x10c
>>>>>>>>> +#define ANACTRL_SYSPLL_CTRL4        0x110
>>>>>>>>> +#define ANACTRL_SYSPLL_STS        0x114
>>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL0        0x140
>>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL1        0x144
>>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL2        0x148
>>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL3        0x14c
>>>>>>>>> +#define ANACTRL_HIFIPLL_CTRL4        0x150
>>>>>>>>> +#define ANACTRL_HIFIPLL_STS        0x154
>>>>>>>>> +#define ANACTRL_AUDDDS_CTRL0        0x180
>>>>>>>>> +#define ANACTRL_AUDDDS_CTRL1        0x184
>>>>>>>>> +#define ANACTRL_AUDDDS_CTRL2        0x188
>>>>>>>>> +#define ANACTRL_AUDDDS_CTRL3        0x18c
>>>>>>>>> +#define ANACTRL_AUDDDS_CTRL4        0x190
>>>>>>>>> +#define ANACTRL_AUDDDS_STS        0x194
>>>>>>>>> +#define ANACTRL_MISCTOP_CTRL0        0x1c0
>>>>>>>>> +#define ANACTRL_POR_CNTL        0x208
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * CLKID index values
>>>>>>>>> + *
>>>>>>>>> + * These indices are entirely contrived and do not map onto the
>>>>>>>>> hardware.
>>>>>>>>> + * It has now been decided to expose everything by default in the
>>>>>>>>> DT header:
>>>>>>>>> + * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we
>>>>>>>>> don't want
>>>>>>>>> + * to expose, such as the internal muxes and dividers of composite
>>>>>>>>> clocks,
>>>>>>>>> + * will remain defined here.
>>>>>>>>> + */
>>>>>>>>> +#define CLKID_FIXED_PLL_DCO        0
>>>>>>>>> +#define CLKID_FCLK_DIV2_DIV        2
>>>>>>>>> +#define CLKID_FCLK_DIV3_DIV        3
>>>>>>>>> +#define CLKID_FCLK_DIV5_DIV        4
>>>>>>>>> +#define CLKID_FCLK_DIV7_DIV        5
>>>>>>>>> +#define NR_PLL_CLKS            11
>>>>>>>>> +
>>>>>>>>> +/* include the CLKIDs that have been made part of the DT binding */
>>>>>>>>> +#include <dt-bindings/clock/a1-pll-clkc.h>
>>>>>>>>> +
>>>>>>>>> +#endif /* __A1_PLL_H */
>>>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..86a4733
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>>>> @@ -0,0 +1,2264 @@
>>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>>> + * Author: Jian Hu <jian.hu@amlogic.com>
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>>> +#include "clk-pll.h"
>>>>>>>>> +#include "clk-dualdiv.h"
>>>>>>>>> +#include "meson-eeclk.h"
>>>>>>>>> +#include "a1.h"
>>>>>>>>
>>>>>>>> Same as above
>>>>>>> OK, I will change the order.
>>>>>>> In fact, the clk-pll.h is not used in the current driver.
>>>>>>> I will remove it.
>>>>>>>>
>>>>>>>>> +
>>>>>>>>> +/* PLLs clock in gates, its parent is xtal */
>>>>>>>>> +static struct clk_regmap a1_xtal_clktree = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>>>> +        .bit_idx = 0,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "xtal_clktree",
>>>>>>>>> +        .ops = &clk_regmap_gate_ro_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>>> +            .fw_name = "xtal",
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * switch for xtal clock
>>>>>>>>> +         * Linux should not change it at runtime
>>>>>>>>> +         */
>>>>>>>>
>>>>>>>> Comment not useful: it uses the Ro ops
>>>>>>>>
>>>>>>> OK,  remove the comments
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_xtal_fixpll = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = SYS_OSCIN_CTRL,
>>>>>>>>> +        .bit_idx = 1,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "xtal_fixpll",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>>> +            .fw_name = "xtal",
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +        /*
>>>>>>>>> +         * it feeds DDR,AXI,APB bus
>>>>>>>>> +         * Linux should not change it at runtime
>>>>>>>>> +         */
>>>>>>>>
>>>>>>>> Again, the child are critical, not directly this clock from your
>>>>>>>> comment.
>>>>>>>>
>>>>>>>> Remove CRITICAL, put RO is linux is not supposed to touch it.
>>>>>>>>
>>>>>>> repace as clk_regmap_gate_ro_ops
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>
>>>>>>> [ ... ]
>>>>>>>
>>>>>>>>> +
>>>>>>>>> +/* dsp a clk */
>>>>>>>>> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
>>>>>>>>> +static const struct clk_parent_data dsp_ab_clk_parent_data[] = {
>>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>>> +    { .fw_name = "fclk_div2", },
>>>>>>>>> +    { .fw_name = "fclk_div3", },
>>>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>>>> +    { .fw_name = "hifi_pll", },
>>>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_a_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x7,
>>>>>>>>> +        .shift = 10,
>>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspa_a_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>>
>>>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>>> Yes, I miss the flag.
>>>>>>>>
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_a_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 10,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspa_a_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_a_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_a = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .bit_idx = 13,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspa_a",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_a_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_b_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x7,
>>>>>>>>> +        .shift = 26,
>>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspa_b_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>>
>>>>>>>> .flags = CLK_SET_RATE_PARENT ?
>>>>>>>>
>>>>>>> Yes, I will add it.
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_b_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .shift = 16,
>>>>>>>>> +        .width = 10,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspa_b_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_b_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_b = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .bit_idx = 29,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspa_b",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_b_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPA_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 15,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspa_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>>> +            { .hw = &a1_dspa_a.hw },
>>>>>>>>> +            { .hw = &a1_dspa_b.hw },
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 2,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_en_dspa = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>>>> +        .bit_idx = 1,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspa_en_dspa",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>
>>>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>>>
>>>>>>> I should remove it
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspa_en_nic = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPA_CLK_EN,
>>>>>>>>> +        .bit_idx = 0,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspa_en_nic",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspa_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>
>>>>>>>> Why do you need CLK_IGNORE_UNUSED ?
>>>>>>>>
>>>>>>> I should remove it
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Same question and remarks applies to DSP B
>>>>>>>>
>>>>>>> got it
>>>>>>>>> +/* dsp b clk */
>>>>>>>>> +static struct clk_regmap a1_dspb_a_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x7,
>>>>>>>>> +        .shift = 10,
>>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspb_a_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_a_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 10,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspb_a_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_a_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_a = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .bit_idx = 13,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspb_a",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_a_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_b_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x7,
>>>>>>>>> +        .shift = 26,
>>>>>>>>> +        .table = mux_table_dsp_ab,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspb_b_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = dsp_ab_clk_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(dsp_ab_clk_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_b_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .shift = 16,
>>>>>>>>> +        .width = 10,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspb_b_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_b_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_b = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .bit_idx = 29,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspb_b",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_b_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DSPB_CLK_CTRL0,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 15,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dspb_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_a.hw, &a1_dspb_b.hw,
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 2,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_en_dspb = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>>>> +        .bit_idx = 1,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspb_en_dspb",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dspb_en_nic = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DSPB_CLK_EN,
>>>>>>>>> +        .bit_idx = 0,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dspb_en_nic",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dspb_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* 12M/24M clock */
>>>>>>>>> +static struct clk_regmap a1_24m = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = CLK12_24_CTRL,
>>>>>>>>> +        .bit_idx = 11,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "24m",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>>> +            .fw_name = "xtal",
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>
>>>>>>> [ ... ]
>>>>>>>
>>>>>>>>> +static struct clk_regmap a1_saradc_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 9,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "saradc_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>>> +            { .fw_name = "xtal", },
>>>>>>>>> +            { .hw = &a1_sys_clk.hw, },
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 2,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_saradc_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "saradc_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_saradc_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_saradc_clk = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = SAR_ADC_CLK_CTRL,
>>>>>>>>> +        .bit_idx = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "saradc_clk",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_saradc_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm a/b/c/d parent data */
>>>>>>>>> +static const struct clk_parent_data pwm_parent_data[] = {
>>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>>>> +};
>>>>>>>>
>>>>>>>> Looks like the same as SAR ADC
>>>>>>>>
>>>>>>> OK, I will describe it like SAR ADC for pwm a/b/c/d
>>>>>>>>> +
>>>>>>>>> +/* pwm a clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_a_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 9,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_a_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_a_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_a_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_a_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_a = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .bit_idx = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_a",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_a_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * The CPU working voltage is controlled by pwm_a
>>>>>>>>> +         * in BL2 firmware. add the CLK_IGNORE_UNUSED flag
>>>>>>>>> +         * to avoid changing at runtime.
>>>>>>>>                                         ^ it
>>>>>>>>
>>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>>                        "blabla. And" is strange
>>>>>>>>
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>>>>>>
>>>>>>>> This only skips the late_init() disable of unused clocks
>>>>>>>>
>>>>>>>> Be aware that this is not fool-proof. If at any time a driver enable
>>>>>>>> then disable the clock, the clock will be disable and I guess your
>>>>>>>> platform will die if this provides the CPU voltage.
>>>>>>> OK, CLK_IS_CRITICAL is better.
>>>>>>>>
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm b clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_b_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 25,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_b_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_b_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .shift = 16,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_b_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_b_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_b = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_AB_CTRL,
>>>>>>>>> +        .bit_idx = 24,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_b",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_b_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm c clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_c_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 9,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_c_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_c_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_c_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_c_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_c = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .bit_idx = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_c",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_c_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm d clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_d_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 25,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_d_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_d_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .shift = 16,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_d_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_d_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_d = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_CD_CTRL,
>>>>>>>>> +        .bit_idx = 24,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_d",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_d_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const struct clk_parent_data pwm_ef_parent_data[] = {
>>>>>>>>> +    { .fw_name = "xtal", },
>>>>>>>>> +    { .hw = &a1_sys_clk.hw },
>>>>>>>>> +    { .fw_name = "fclk_div5", },
>>>>>>>>> +    { .hw = &a1_rtc_clk.hw },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm e clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_e_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .mask = 0x3,
>>>>>>>>> +        .shift = 9,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_e_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_e_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_e_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_e_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_e = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .bit_idx = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_e",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_e_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* pwm f clk */
>>>>>>>>> +static struct clk_regmap a1_pwm_f_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .mask = 0x3,
>>>>>>>>> +        .shift = 25,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_f_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = pwm_ef_parent_data,
>>>>>>>>> +        .num_parents = ARRAY_SIZE(pwm_ef_parent_data),
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_f_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .shift = 16,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "pwm_f_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_f_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_pwm_f = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = PWM_CLK_EF_CTRL,
>>>>>>>>> +        .bit_idx = 24,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "pwm_f",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_pwm_f_div.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>
>>>>>>> [ ... ]
>>>>>>>
>>>>>>>>> +
>>>>>>>>> +/* dmc clk */
>>>>>>>>> +static struct clk_regmap a1_dmc_sel = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>>> +        .mask = 0x3,
>>>>>>>>> +        .shift = 9,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dmc_sel",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = sd_emmc_parents,
>>>>>>>>> +        .num_parents = 4,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dmc_div = {
>>>>>>>>> +    .data = &(struct clk_regmap_div_data){
>>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>>> +        .shift = 0,
>>>>>>>>> +        .width = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dmc_div",
>>>>>>>>> +        .ops = &clk_regmap_divider_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dmc_sel.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dmc_sel2 = {
>>>>>>>>> +    .data = &(struct clk_regmap_mux_data){
>>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>>> +        .mask = 0x1,
>>>>>>>>> +        .shift = 15,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "dmc_sel2",
>>>>>>>>> +        .ops = &clk_regmap_mux_ops,
>>>>>>>>> +        .parent_data = (const struct clk_parent_data []) {
>>>>>>>>> +            { .hw = &a1_dmc_div.hw },
>>>>>>>>> +            { .fw_name = "xtal", },
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 2,
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct clk_regmap a1_dmc = {
>>>>>>>>> +    .data = &(struct clk_regmap_gate_data){
>>>>>>>>> +        .offset = DMC_CLK_CTRL,
>>>>>>>>> +        .bit_idx = 8,
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data) {
>>>>>>>>> +        .name = "dmc",
>>>>>>>>> +        .ops = &clk_regmap_gate_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_dmc_sel2.hw
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        /*
>>>>>>>>> +         * This clock is used by DDR clock which setted in BL2
>>>>>>>>> +         * and is required by the platform to operate correctly.
>>>>>>>>> +         * Until the following condition are met, we need this
>>>>>>>>> clock to
>>>>>>>>> +         * be marked as critical:
>>>>>>>>> +         * a) Mark the clock used by a firmware resource, if
>>>>>>>>> possible
>>>>>>>>> +         * b) CCF has a clock hand-off mechanism to make the sure
>>>>>>>>> the
>>>>>>>>> +         *    clock stays on until the proper driver comes along
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>
>>>>>>>> Should you put all this DMC stuff in RO until you got a driver for
>>>>>>>> it ?
>>>>>>> OK, replace as clk_regmap_gate_ro_ops
>>>>>>>>
>>>>>>> [ ... ]
>>>>>>>>> +
>>>>>>>>> +static int meson_a1_periphs_probe(struct platform_device *pdev)
>>>>>>>>> +{
>>>>>>>>> +    int ret;
>>>>>>>>> +
>>>>>>>>> +    ret = meson_eeclkc_probe(pdev);
>>>>>>>>> +    if (ret)
>>>>>>>>> +        return ret;
>>>>>>>>> +
>>>>>>>>> +    return 0;
>>>>>>>>> +}
>>>>>>>>
>>>>>>>> Again this function is function is useless and it makes me wonder if
>>>>>>>> you
>>>>>>>> should really be using meson_eeclkc_probe()
>>>>>>>>
>>>>>>>> This makes you use syscon which is not correct unless you have a good
>>>>>>>> reason ?
>>>>>>>>
>>>>>>> If it can not use the meson_eeclkc_probe(), I will realize a probe
>>>>>>> function
>>>>>>> which is mostly duplicate with meson_eeclkc_probe() except
>>>>>>> "syscon_node_to_regmap"
>>>>>>>
>>>>>>> Maybe another common probe function and a new file are required for A1
>>>>>>> three drivers? (include the CPU clock driver)
>>>>>>
>>>>>> Maybe
>>>>>>
>>>>> I will add a new function base on meson-eeclk.c
>>>>>>>
>>>>>>> Or using meson_eeclkc_probe is more easier?
>>>>>>
>>>>>> It is not question of easiness, but correctness.
>>>>>>
>>>>>>>
>>>>>>>> Is there anything but clocks and resets in these register region ?
>>>>>>> No, there is only clocks in the register region.
>>>>>>> the same does the PLL register region.
>>>>>>
>>>>>> Then there is no reason to use syscon for those drivers
>>>>>> Add a new probe function for A1
>>>>>>>>
>>>>>>>>> +
>>>>>>>>> +static const struct meson_eeclkc_data a1_periphs_data = {
>>>>>>>>> +        .regmap_clks = a1_periphs_regmaps,
>>>>>>>>> +        .regmap_clk_num = ARRAY_SIZE(a1_periphs_regmaps),
>>>>>>>>> +        .hw_onecell_data = &a1_periphs_hw_onecell_data,
>>>>>>>>> +};
>>>>>>>>> +static const struct of_device_id clkc_match_table[] = {
>>>>>>>>> +    {
>>>>>>>>> +        .compatible = "amlogic,a1-periphs-clkc",
>>>>>>>>> +        .data = &a1_periphs_data
>>>>>>>>> +    },
>>>>>>>>> +    { /* sentinel */ }
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static struct platform_driver a1_driver = {
>>>>>>>>> +    .probe        = meson_a1_periphs_probe,
>>>>>>>>> +    .driver        = {
>>>>>>>>> +        .name    = "a1-periphs-clkc",
>>>>>>>>> +        .of_match_table = clkc_match_table,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +builtin_platform_driver(a1_driver);
>>>>>>>>> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..1ae5e04
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/clk/meson/a1.h
>>>>>>>>> @@ -0,0 +1,120 @@
>>>>>>>>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#ifndef __A1_H
>>>>>>>>> +#define __A1_H
>>>>>>>>> +
>>>>>>>>> +/* peripheral clock controller register offset */
>>>>>>>>> +#define SYS_OSCIN_CTRL            0x0
>>>>>>>>> +#define RTC_BY_OSCIN_CTRL0        0x4
>>>>>>>>> +#define RTC_BY_OSCIN_CTRL1        0x8
>>>>>>>>> +#define RTC_CTRL            0xc
>>>>>>>>> +#define SYS_CLK_CTRL0            0x10
>>>>>>>>> +#define AXI_CLK_CTRL0            0x14
>>>>>>>>> +#define SYS_CLK_EN0            0x1c
>>>>>>>>> +#define SYS_CLK_EN1            0x20
>>>>>>>>> +#define AXI_CLK_EN            0x24
>>>>>>>>> +#define DSPA_CLK_EN            0x28
>>>>>>>>> +#define DSPB_CLK_EN            0x2c
>>>>>>>>> +#define DSPA_CLK_CTRL0            0x30
>>>>>>>>> +#define DSPB_CLK_CTRL0            0x34
>>>>>>>>> +#define CLK12_24_CTRL            0x38
>>>>>>>>> +#define GEN_CLK_CTRL            0x3c
>>>>>>>>> +#define TIMESTAMP_CTRL0            0x40
>>>>>>>>> +#define TIMESTAMP_CTRL1            0x44
>>>>>>>>> +#define TIMESTAMP_CTRL2            0x48
>>>>>>>>> +#define TIMESTAMP_VAL0            0x4c
>>>>>>>>> +#define TIMESTAMP_VAL1            0x50
>>>>>>>>> +#define TIMEBASE_CTRL0            0x54
>>>>>>>>> +#define TIMEBASE_CTRL1            0x58
>>>>>>>>> +#define SAR_ADC_CLK_CTRL        0xc0
>>>>>>>>> +#define PWM_CLK_AB_CTRL            0xc4
>>>>>>>>> +#define PWM_CLK_CD_CTRL            0xc8
>>>>>>>>> +#define PWM_CLK_EF_CTRL            0xcc
>>>>>>>>> +#define SPICC_CLK_CTRL            0xd0
>>>>>>>>> +#define TS_CLK_CTRL            0xd4
>>>>>>>>> +#define SPIFC_CLK_CTRL            0xd8
>>>>>>>>> +#define USB_BUSCLK_CTRL            0xdc
>>>>>>>>> +#define SD_EMMC_CLK_CTRL        0xe0
>>>>>>>>> +#define CECA_CLK_CTRL0            0xe4
>>>>>>>>> +#define CECA_CLK_CTRL1            0xe8
>>>>>>>>> +#define CECB_CLK_CTRL0            0xec
>>>>>>>>> +#define CECB_CLK_CTRL1            0xf0
>>>>>>>>> +#define PSRAM_CLK_CTRL            0xf4
>>>>>>>>> +#define DMC_CLK_CTRL            0xf8
>>>>>>>>> +#define FCLK_DIV1_SEL            0xfc
>>>>>>>>> +#define TST_CTRL            0x100
>>>>>>>>> +
>>>>>>>>> +#define CLKID_XTAL_CLKTREE        0
>>>>>>>>> +#define CLKID_SYS_A_SEL            89
>>>>>>>>> +#define CLKID_SYS_A_DIV            90
>>>>>>>>> +#define CLKID_SYS_A            91
>>>>>>>>> +#define CLKID_SYS_B_SEL            92
>>>>>>>>> +#define CLKID_SYS_B_DIV            93
>>>>>>>>> +#define CLKID_SYS_B            94
>>>>>>>>> +#define CLKID_DSPA_A_SEL        95
>>>>>>>>> +#define CLKID_DSPA_A_DIV        96
>>>>>>>>> +#define CLKID_DSPA_A            97
>>>>>>>>> +#define CLKID_DSPA_B_SEL        98
>>>>>>>>> +#define CLKID_DSPA_B_DIV        99
>>>>>>>>> +#define CLKID_DSPA_B            100
>>>>>>>>> +#define CLKID_DSPB_A_SEL        101
>>>>>>>>> +#define CLKID_DSPB_A_DIV        102
>>>>>>>>> +#define CLKID_DSPB_A            103
>>>>>>>>> +#define CLKID_DSPB_B_SEL        104
>>>>>>>>> +#define CLKID_DSPB_B_DIV        105
>>>>>>>>> +#define CLKID_DSPB_B            106
>>>>>>>>> +#define CLKID_RTC_32K_CLKIN        107
>>>>>>>>> +#define CLKID_RTC_32K_DIV        108
>>>>>>>>> +#define CLKID_RTC_32K_XTAL        109
>>>>>>>>> +#define CLKID_RTC_32K_SEL        110
>>>>>>>>> +#define CLKID_CECB_32K_CLKIN        111
>>>>>>>>> +#define CLKID_CECB_32K_DIV        112
>>>>>>>>> +#define CLKID_CECB_32K_SEL_PRE        113
>>>>>>>>> +#define CLKID_CECB_32K_SEL        114
>>>>>>>>> +#define CLKID_CECA_32K_CLKIN        115
>>>>>>>>> +#define CLKID_CECA_32K_DIV        116
>>>>>>>>> +#define CLKID_CECA_32K_SEL_PRE        117
>>>>>>>>> +#define CLKID_CECA_32K_SEL        118
>>>>>>>>> +#define CLKID_DIV2_PRE            119
>>>>>>>>> +#define CLKID_24M_DIV2            120
>>>>>>>>> +#define CLKID_GEN_SEL            121
>>>>>>>>> +#define CLKID_GEN_DIV            122
>>>>>>>>> +#define CLKID_SARADC_DIV        123
>>>>>>>>> +#define CLKID_PWM_A_SEL            124
>>>>>>>>> +#define CLKID_PWM_A_DIV            125
>>>>>>>>> +#define CLKID_PWM_B_SEL            126
>>>>>>>>> +#define CLKID_PWM_B_DIV            127
>>>>>>>>> +#define CLKID_PWM_C_SEL            128
>>>>>>>>> +#define CLKID_PWM_C_DIV            129
>>>>>>>>> +#define CLKID_PWM_D_SEL            130
>>>>>>>>> +#define CLKID_PWM_D_DIV            131
>>>>>>>>> +#define CLKID_PWM_E_SEL            132
>>>>>>>>> +#define CLKID_PWM_E_DIV            133
>>>>>>>>> +#define CLKID_PWM_F_SEL            134
>>>>>>>>> +#define CLKID_PWM_F_DIV            135
>>>>>>>>> +#define CLKID_SPICC_SEL            136
>>>>>>>>> +#define CLKID_SPICC_DIV            137
>>>>>>>>> +#define CLKID_SPICC_SEL2        138
>>>>>>>>> +#define CLKID_TS_DIV            139
>>>>>>>>> +#define CLKID_SPIFC_SEL            140
>>>>>>>>> +#define CLKID_SPIFC_DIV            141
>>>>>>>>> +#define CLKID_SPIFC_SEL2        142
>>>>>>>>> +#define CLKID_USB_BUS_SEL        143
>>>>>>>>> +#define CLKID_USB_BUS_DIV        144
>>>>>>>>> +#define CLKID_SD_EMMC_SEL        145
>>>>>>>>> +#define CLKID_SD_EMMC_DIV        146
>>>>>>>>> +#define CLKID_SD_EMMC_SEL2        147
>>>>>>>>> +#define CLKID_PSRAM_SEL            148
>>>>>>>>> +#define CLKID_PSRAM_DIV            149
>>>>>>>>> +#define CLKID_PSRAM_SEL2        150
>>>>>>>>> +#define CLKID_DMC_SEL            151
>>>>>>>>> +#define CLKID_DMC_DIV            152
>>>>>>>>> +#define CLKID_DMC_SEL2            153
>>>>>>>>> +#define NR_CLKS                154
>>>>>>>>> +
>>>>>>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>>>>>>> +
>>>>>>>>> +#endif /* __A1_H */
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>
>>>>>> .
>>>>>>
>>>>
>>>> .
>>>>
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-21  3:21                   ` Jian Hu
@ 2019-11-25 10:14                     ` Jerome Brunet
  2019-11-25 12:01                       ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-11-25 10:14 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Thu 21 Nov 2019 at 04:21, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Jerome
>
> On 2019/11/20 23:35, Jerome Brunet wrote:
>>
>> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> Hi, jerome
>>>
>>> Is there any problem about fixed_pll_dco's parent_data?
>>>
>>> Now both name and fw_name are described in parent_data.
>>
>> Yes, there is a problem.  This approach is incorrect, as I've tried to
>> explain a couple times already. Let me try to re-summarize why this
>> approach is incorrect.
>>
>> Both fw_name and name should be provided when it is possible that
>> the DT does not describe the input clock. IOW, it is only for controllers
>> which relied on the global name so far and are now starting to describe
>> the clock input in DT
>>
>> This is not your case.
>> Your controller is new and DT will have the correct
>> info
>>
>> You are trying work around an ordering issue by providing both fw_name
>> and name. This is not correct and I'll continue to nack it.
>>
>> If the orphan clock is not reparented as you would expect, I suggest you
>> try to look a bit further at how the reparenting of orphans is done in
>> CCF and why it does not match your expectation.
>>
> I have debugged the handle for orphan clock in CCF, Maybe you are missing
> the last email.

Nope, got it the first time

> Even though the clock index exit, it will get failed for the orphan clock's
> parent clock due to it has not beed added to the provider.

If the provider is not registered yet, of course any query to it won't
work. This why I have suggested to this debug *further* :

* Is the orphan reparenting done when a new provider is registered ?
* If not, should it be done ? is this your problem ?



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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-25 10:14                     ` Jerome Brunet
@ 2019-11-25 12:01                       ` Jian Hu
  2019-11-25 12:30                         ` Jerome Brunet
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-25 12:01 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel



On 2019/11/25 18:14, Jerome Brunet wrote:
> 
> On Thu 21 Nov 2019 at 04:21, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Jerome
>>
>> On 2019/11/20 23:35, Jerome Brunet wrote:
>>>
>>> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> Hi, jerome
>>>>
>>>> Is there any problem about fixed_pll_dco's parent_data?
>>>>
>>>> Now both name and fw_name are described in parent_data.
>>>
>>> Yes, there is a problem.  This approach is incorrect, as I've tried to
>>> explain a couple times already. Let me try to re-summarize why this
>>> approach is incorrect.
>>>
>>> Both fw_name and name should be provided when it is possible that
>>> the DT does not describe the input clock. IOW, it is only for controllers
>>> which relied on the global name so far and are now starting to describe
>>> the clock input in DT
>>>
>>> This is not your case.
>>> Your controller is new and DT will have the correct
>>> info
>>>
>>> You are trying work around an ordering issue by providing both fw_name
>>> and name. This is not correct and I'll continue to nack it.
>>>
>>> If the orphan clock is not reparented as you would expect, I suggest you
>>> try to look a bit further at how the reparenting of orphans is done in
>>> CCF and why it does not match your expectation.
>>>
>> I have debugged the handle for orphan clock in CCF, Maybe you are missing
>> the last email.
> 
> Nope, got it the first time
> 
>> Even though the clock index exit, it will get failed for the orphan clock's
>> parent clock due to it has not beed added to the provider.
> 
> If the provider is not registered yet, of course any query to it won't
> work. This why I have suggested to this debug *further* :
> 
> * Is the orphan reparenting done when a new provider is registered ?
> * If not, should it be done ? is this your problem ?
> 
Yes, the orphan reparenting is done when the new provider is registered.

Reparenting the orphan will be done when each clock is registered by 
devm_clk_hw_register. And at this time the provider has not been 
registered. After all clocks are registered by devm_clk_hw_register, the
provider will be registered by devm_of_clk_add_hw_provider.

Reparenting the orphan will fail when fw_name is added alone, the couse 
is that devm_clk_hw_register is always running ahead of 
devm_of_clk_add_hw_provider.

That is why it will failed to get parent for the orphan clock.



> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-25 12:01                       ` Jian Hu
@ 2019-11-25 12:30                         ` Jerome Brunet
  2019-11-25 13:51                           ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jerome Brunet @ 2019-11-25 12:30 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel


On Mon 25 Nov 2019 at 13:01, Jian Hu <jian.hu@amlogic.com> wrote:

> On 2019/11/25 18:14, Jerome Brunet wrote:
>>
>> On Thu 21 Nov 2019 at 04:21, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> Hi, Jerome
>>>
>>> On 2019/11/20 23:35, Jerome Brunet wrote:
>>>>
>>>> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> Hi, jerome
>>>>>
>>>>> Is there any problem about fixed_pll_dco's parent_data?
>>>>>
>>>>> Now both name and fw_name are described in parent_data.
>>>>
>>>> Yes, there is a problem.  This approach is incorrect, as I've tried to
>>>> explain a couple times already. Let me try to re-summarize why this
>>>> approach is incorrect.
>>>>
>>>> Both fw_name and name should be provided when it is possible that
>>>> the DT does not describe the input clock. IOW, it is only for controllers
>>>> which relied on the global name so far and are now starting to describe
>>>> the clock input in DT
>>>>
>>>> This is not your case.
>>>> Your controller is new and DT will have the correct
>>>> info
>>>>
>>>> You are trying work around an ordering issue by providing both fw_name
>>>> and name. This is not correct and I'll continue to nack it.
>>>>
>>>> If the orphan clock is not reparented as you would expect, I suggest you
>>>> try to look a bit further at how the reparenting of orphans is done in
>>>> CCF and why it does not match your expectation.
>>>>
>>> I have debugged the handle for orphan clock in CCF, Maybe you are missing
>>> the last email.
>>
>> Nope, got it the first time
>>
>>> Even though the clock index exit, it will get failed for the orphan clock's
>>> parent clock due to it has not beed added to the provider.
>>
>> If the provider is not registered yet, of course any query to it won't
>> work. This why I have suggested to this debug *further* :
>>
>> * Is the orphan reparenting done when a new provider is registered ?
>> * If not, should it be done ? is this your problem ?
>>

Apparently, I was not clear enough so I'll rephrase

> Yes, the orphan reparenting is done when the new provider is
> registered.

No it is not done yet. Please check the code.

The reparenting of orphan is done only on clock registration, not on
provider registeration. Now that clocks can be specified by DT, this
probably needs to added.

That is your problem.

Please fix the underlying issue, then you can post your series again.

>
> Reparenting the orphan will be done when each clock is registered by
> devm_clk_hw_register. And at this time the provider has not been
> registered. After all clocks are registered by devm_clk_hw_register, the
> provider will be registered by devm_of_clk_add_hw_provider.
>
> Reparenting the orphan will fail when fw_name is added alone, the couse is
> that devm_clk_hw_register is always running ahead of
> devm_of_clk_add_hw_provider.

Please stop bringing the topic of "fw_name" and "name" field together, I
told you 3 times why this is wrong. It is not going to change.

>
> That is why it will failed to get parent for the orphan clock.

It fails because the provider is not registered when you try to reparent
the orphan.

It shows that you should try again once the provider is registered.

>
>
>
>>
>> .
>>


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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-25 12:30                         ` Jerome Brunet
@ 2019-11-25 13:51                           ` Jian Hu
  2019-11-26  2:35                             ` Jian Hu
  0 siblings, 1 reply; 22+ messages in thread
From: Jian Hu @ 2019-11-25 13:51 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel



On 2019/11/25 20:30, Jerome Brunet wrote:
> 
> On Mon 25 Nov 2019 at 13:01, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> On 2019/11/25 18:14, Jerome Brunet wrote:
>>>
>>> On Thu 21 Nov 2019 at 04:21, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> Hi, Jerome
>>>>
>>>> On 2019/11/20 23:35, Jerome Brunet wrote:
>>>>>
>>>>> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>
>>>>>> Hi, jerome
>>>>>>
>>>>>> Is there any problem about fixed_pll_dco's parent_data?
>>>>>>
>>>>>> Now both name and fw_name are described in parent_data.
>>>>>
>>>>> Yes, there is a problem.  This approach is incorrect, as I've tried to
>>>>> explain a couple times already. Let me try to re-summarize why this
>>>>> approach is incorrect.
>>>>>
>>>>> Both fw_name and name should be provided when it is possible that
>>>>> the DT does not describe the input clock. IOW, it is only for controllers
>>>>> which relied on the global name so far and are now starting to describe
>>>>> the clock input in DT
>>>>>
>>>>> This is not your case.
>>>>> Your controller is new and DT will have the correct
>>>>> info
>>>>>
>>>>> You are trying work around an ordering issue by providing both fw_name
>>>>> and name. This is not correct and I'll continue to nack it.
>>>>>
>>>>> If the orphan clock is not reparented as you would expect, I suggest you
>>>>> try to look a bit further at how the reparenting of orphans is done in
>>>>> CCF and why it does not match your expectation.
>>>>>
>>>> I have debugged the handle for orphan clock in CCF, Maybe you are missing
>>>> the last email.
>>>
>>> Nope, got it the first time
>>>
>>>> Even though the clock index exit, it will get failed for the orphan clock's
>>>> parent clock due to it has not beed added to the provider.
>>>
>>> If the provider is not registered yet, of course any query to it won't
>>> work. This why I have suggested to this debug *further* :
>>>
>>> * Is the orphan reparenting done when a new provider is registered ?
>>> * If not, should it be done ? is this your problem ?
>>>
> 
> Apparently, I was not clear enough so I'll rephrase
> 
>> Yes, the orphan reparenting is done when the new provider is
>> registered.
> 
> No it is not done yet. Please check the code.
> 
> The reparenting of orphan is done only on clock registration, not on
> provider registeration. Now that clocks can be specified by DT, this
> probably needs to added.The action of reparenting the orphan is before the provider registration 
with the current code.
> 
> That is your problem.
Yes, if the provider is registered before the clock registration, it
will reparent successfully.
> 
> Please fix the underlying issue, then you can post your series again.
> 
>>
>> Reparenting the orphan will be done when each clock is registered by
>> devm_clk_hw_register. And at this time the provider has not been
>> registered. After all clocks are registered by devm_clk_hw_register, the
>> provider will be registered by devm_of_clk_add_hw_provider.
>>
>> Reparenting the orphan will fail when fw_name is added alone, the couse is
>> that devm_clk_hw_register is always running ahead of
>> devm_of_clk_add_hw_provider.
> 
> Please stop bringing the topic of "fw_name" and "name" field together, I
> told you 3 times why this is wrong. It is not going to change.
> 
>>
>> That is why it will failed to get parent for the orphan clock.
> 
> It fails because the provider is not registered when you try to reparent
> the orphan.
> 
> It shows that you should try again once the provider is registered.
> 
OK, I have exchanged the position for devm_clk_hw_register and 
devm_of_clk_add_hw_provider in meson-eeclk.c.

It reparents successfully for orphan clock.

Is is ok that put devm_of_clk_add_hw_provider ahead?

As far as I am concerned, there is no any effect.
>>
>>
>>
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-11-25 13:51                           ` Jian Hu
@ 2019-11-26  2:35                             ` Jian Hu
  0 siblings, 0 replies; 22+ messages in thread
From: Jian Hu @ 2019-11-26  2:35 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, Jianxin Pan,
	Victor Wan, Chandle Zou, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel



On 2019/11/25 21:51, Jian Hu wrote:
> 
> 
> On 2019/11/25 20:30, Jerome Brunet wrote:
>>
>> On Mon 25 Nov 2019 at 13:01, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> On 2019/11/25 18:14, Jerome Brunet wrote:
>>>>
>>>> On Thu 21 Nov 2019 at 04:21, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> Hi, Jerome
>>>>>
>>>>> On 2019/11/20 23:35, Jerome Brunet wrote:
>>>>>>
>>>>>> On Wed 20 Nov 2019 at 10:28, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>
>>>>>>> Hi, jerome
>>>>>>>
>>>>>>> Is there any problem about fixed_pll_dco's parent_data?
>>>>>>>
>>>>>>> Now both name and fw_name are described in parent_data.
>>>>>>
>>>>>> Yes, there is a problem.  This approach is incorrect, as I've 
>>>>>> tried to
>>>>>> explain a couple times already. Let me try to re-summarize why this
>>>>>> approach is incorrect.
>>>>>>
>>>>>> Both fw_name and name should be provided when it is possible that
>>>>>> the DT does not describe the input clock. IOW, it is only for 
>>>>>> controllers
>>>>>> which relied on the global name so far and are now starting to 
>>>>>> describe
>>>>>> the clock input in DT
>>>>>>
>>>>>> This is not your case.
>>>>>> Your controller is new and DT will have the correct
>>>>>> info
>>>>>>
>>>>>> You are trying work around an ordering issue by providing both 
>>>>>> fw_name
>>>>>> and name. This is not correct and I'll continue to nack it.
>>>>>>
>>>>>> If the orphan clock is not reparented as you would expect, I 
>>>>>> suggest you
>>>>>> try to look a bit further at how the reparenting of orphans is 
>>>>>> done in
>>>>>> CCF and why it does not match your expectation.
>>>>>>
>>>>> I have debugged the handle for orphan clock in CCF, Maybe you are 
>>>>> missing
>>>>> the last email.
>>>>
>>>> Nope, got it the first time
>>>>
>>>>> Even though the clock index exit, it will get failed for the orphan 
>>>>> clock's
>>>>> parent clock due to it has not beed added to the provider.
>>>>
>>>> If the provider is not registered yet, of course any query to it won't
>>>> work. This why I have suggested to this debug *further* :
>>>>
>>>> * Is the orphan reparenting done when a new provider is registered ?
>>>> * If not, should it be done ? is this your problem ?
>>>>
>>
>> Apparently, I was not clear enough so I'll rephrase
>>
>>> Yes, the orphan reparenting is done when the new provider is
>>> registered.
>>
>> No it is not done yet. Please check the code.
>>
>> The reparenting of orphan is done only on clock registration, not on
>> provider registeration. Now that clocks can be specified by DT, this
>> probably needs to added.The action of reparenting the orphan is before 
>> the provider registration 
> with the current code.
>>
>> That is your problem.
> Yes, if the provider is registered before the clock registration, it
> will reparent successfully.
>>
>> Please fix the underlying issue, then you can post your series again.
>>
>>>
>>> Reparenting the orphan will be done when each clock is registered by
>>> devm_clk_hw_register. And at this time the provider has not been
>>> registered. After all clocks are registered by devm_clk_hw_register, the
>>> provider will be registered by devm_of_clk_add_hw_provider.
>>>
>>> Reparenting the orphan will fail when fw_name is added alone, the 
>>> couse is
>>> that devm_clk_hw_register is always running ahead of
>>> devm_of_clk_add_hw_provider.
>>
>> Please stop bringing the topic of "fw_name" and "name" field together, I
>> told you 3 times why this is wrong. It is not going to change.
>>
>>>
>>> That is why it will failed to get parent for the orphan clock.
>>
>> It fails because the provider is not registered when you try to reparent
>> the orphan.
>>
>> It shows that you should try again once the provider is registered.
>>
> OK, I have exchanged the position for devm_clk_hw_register and 
> devm_of_clk_add_hw_provider in meson-eeclk.c.
> 
> It reparents successfully for orphan clock.
> 
> Is is ok that put devm_of_clk_add_hw_provider ahead?
> 
> As far as I am concerned, there is no any effect.Sorry, If the provider is registered first, I find it will affect the 
assigned-clock-parents and assigned-clock-rates configurations in DT 
when the provider is registered.

It will fail to set the assigned parent and assigned rate for one clock 
because of the related clocks are not registered yet.

Moreover, registering provider is always after clock registration in 
other vendor clock drivers.

Maybe registering provider is better after the clock registration.


>>>
>>>
>>>
>>>>
>>>> .
>>>>
>>
>> .
>>

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

end of thread, other threads:[~2019-11-26  2:34 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-18  7:14 [PATCH v2 0/3] add Amlogic A1 clock controller driver Jian Hu
2019-10-18  7:14 ` [PATCH v2 1/3] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
2019-10-21 10:43   ` Jerome Brunet
2019-10-22  5:30     ` Jian Hu
2019-10-18  7:14 ` [PATCH v2 2/3] clk: meson: add support for A1 PLL clock ops Jian Hu
2019-10-21 11:31   ` Jerome Brunet
2019-10-25  6:47     ` Jian Hu
2019-10-18  7:14 ` [PATCH v2 3/3] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
2019-10-21 11:41   ` Jerome Brunet
2019-10-25 11:32     ` Jian Hu
2019-11-04  8:24       ` Jerome Brunet
2019-11-09 11:16         ` Jian Hu
2019-11-12 16:59           ` Jerome Brunet
2019-11-13 14:21             ` Jian Hu
2019-11-20  9:28               ` Jian Hu
2019-11-20 15:35                 ` Jerome Brunet
2019-11-21  3:21                   ` Jian Hu
2019-11-25 10:14                     ` Jerome Brunet
2019-11-25 12:01                       ` Jian Hu
2019-11-25 12:30                         ` Jerome Brunet
2019-11-25 13:51                           ` Jian Hu
2019-11-26  2:35                             ` Jian Hu

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