linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] add Amlogic A1 clock controller driver
@ 2019-09-25 11:44 Jian Hu
  2019-09-25 11:44 ` [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
  2019-09-25 11:44 ` [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
  0 siblings, 2 replies; 20+ messages in thread
From: Jian Hu @ 2019-09-25 11:44 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,
	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.

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

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

 .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |   65 +
 arch/arm64/Kconfig.platforms                       |    1 +
 drivers/clk/meson/Kconfig                          |   10 +
 drivers/clk/meson/Makefile                         |    1 +
 drivers/clk/meson/a1.c                             | 2617 ++++++++++++++++++++
 drivers/clk/meson/a1.h                             |  172 ++
 include/dt-bindings/clock/a1-clkc.h                |  102 +
 7 files changed, 2968 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
 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

-- 
1.9.1


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

* [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-09-25 11:44 [PATCH 0/2] add Amlogic A1 clock controller driver Jian Hu
@ 2019-09-25 11:44 ` Jian Hu
  2019-09-25 14:29   ` Jerome Brunet
  2019-09-27 20:10   ` Rob Herring
  2019-09-25 11:44 ` [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
  1 sibling, 2 replies; 20+ messages in thread
From: Jian Hu @ 2019-09-25 11:44 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, 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>
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
---
 .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  65 +++++++++++++
 include/dt-bindings/clock/a1-clkc.h                | 102 +++++++++++++++++++++
 2 files changed, 167 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
 create mode 100644 include/dt-bindings/clock/a1-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..f012eb2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
@@ -0,0 +1,65 @@
+/* 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 A1 Clock Control Unit Device Tree Bindings
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+  - Jerome Brunet <jbrunet@baylibre.com>
+  - Jian Hu <jian.hu@jian.hu.com>
+
+properties:
+  compatible:
+    - enum:
+        - amlogic,a1-clkc
+
+  reg:
+    minItems: 1
+    maxItems: 3
+    items:
+      - description: peripheral registers
+      - description: cpu registers
+      - description: pll registers
+
+  reg-names:
+    items:
+      - const: peripheral
+      - const: pll
+      - const: cpu
+
+  clocks:
+    maxItems: 1
+    items:
+      - description: Input Oscillator (usually at 24MHz)
+
+  clock-names:
+    maxItems: 1
+    items:
+      - const: xtal
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - "#clock-cells"
+
+examples:
+  - |
+    clkc: clock-controller {
+        compatible = "amlogic,a1-clkc";
+        reg = <0x0 0xfe000800 0x0 0x100>,
+              <0x0 0xfe007c00 0x0 0x21c>,
+              <0x0 0xfd000080 0x0 0x20>;
+        reg-names = "peripheral", "pll", "cpu";
+        clocks = <&xtal;
+        clock-names = "xtal";
+        #clock-cells = <1>;
+    };
diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h
new file mode 100644
index 0000000..69fbf37
--- /dev/null
+++ b/include/dt-bindings/clock/a1-clkc.h
@@ -0,0 +1,102 @@
+/* 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_FIXED_PLL				1
+#define CLKID_FCLK_DIV2				2
+#define CLKID_FCLK_DIV3				3
+#define CLKID_FCLK_DIV5				4
+#define CLKID_FCLK_DIV7				5
+#define CLKID_FCLK_DIV2_DIV			6
+#define CLKID_FCLK_DIV3_DIV			7
+#define CLKID_FCLK_DIV5_DIV			8
+#define CLKID_FCLK_DIV7_DIV			9
+#define CLKID_SYS_CLK				16
+#define CLKID_HIFI_PLL				17
+#define CLKID_CLKTREE				25
+#define CLKID_RESET_CTRL			26
+#define CLKID_ANALOG_CTRL			27
+#define CLKID_PWR_CTRL				28
+#define CLKID_PAD_CTRL				29
+#define CLKID_SYS_CTRL				30
+#define CLKID_TEMP_SENSOR			31
+#define CLKID_AM2AXI_DIV			32
+#define CLKID_SPICC_B				33
+#define CLKID_SPICC_A				34
+#define CLKID_CLK_MSR				35
+#define CLKID_AUDIO				36
+#define CLKID_JTAG_CTRL				37
+#define CLKID_SARADC				38
+#define CLKID_PWM_EF				39
+#define CLKID_PWM_CD				40
+#define CLKID_PWM_AB				41
+#define CLKID_CEC				42
+#define CLKID_I2C_S				43
+#define CLKID_IR_CTRL				44
+#define CLKID_I2C_M_D				45
+#define CLKID_I2C_M_C				46
+#define CLKID_I2C_M_B				47
+#define CLKID_I2C_M_A				48
+#define CLKID_ACODEC				49
+#define CLKID_OTP				50
+#define CLKID_SD_EMMC_A				51
+#define CLKID_USB_PHY				52
+#define CLKID_USB_CTRL				53
+#define CLKID_SYS_DSPB				54
+#define CLKID_SYS_DSPA				55
+#define CLKID_DMA				56
+#define CLKID_IRQ_CTRL				57
+#define CLKID_NIC				58
+#define CLKID_GIC				59
+#define CLKID_UART_C				60
+#define CLKID_UART_B				61
+#define CLKID_UART_A				62
+#define CLKID_SYS_PSRAM				63
+#define CLKID_RSA				64
+#define CLKID_CORESIGHT				65
+#define CLKID_AM2AXI_VAD			66
+#define CLKID_AUDIO_VAD				67
+#define CLKID_AXI_DMC				68
+#define CLKID_AXI_PSRAM				69
+#define CLKID_RAMB				70
+#define CLKID_RAMA				71
+#define CLKID_AXI_SPIFC				72
+#define CLKID_AXI_NIC				73
+#define CLKID_AXI_DMA				74
+#define CLKID_CPU_CTRL				75
+#define CLKID_ROM				76
+#define CLKID_PROC_I2C				77
+#define CLKID_DSPA_SEL				84
+#define CLKID_DSPB_SEL				91
+#define CLKID_DSPA_EN_DSPA			92
+#define CLKID_DSPA_EN_NIC			93
+#define CLKID_DSPB_EN_DSPB			94
+#define CLKID_DSPB_EN_NIC			95
+#define CLKID_RTC_CLK				100
+#define CLKID_CECA_32K				105
+#define CLKID_CECB_32K				110
+#define CLKID_24M				111
+#define CLKID_12M				112
+#define CLKID_FCLK_DIV2_DIVN			114
+#define CLKID_GEN				118
+#define CLKID_SARADC_SEL			119
+#define CLKID_SARADC_CLK			121
+#define CLKID_PWM_A				124
+#define CLKID_PWM_B				127
+#define CLKID_PWM_C				130
+#define CLKID_PWM_D				133
+#define CLKID_PWM_E				136
+#define CLKID_PWM_F				139
+#define CLKID_SPICC				143
+#define CLKID_TS				145
+#define CLKID_SPIFC				149
+#define CLKID_USB_BUS				152
+#define CLKID_SD_EMMC				156
+#define CLKID_PSRAM				160
+#define CLKID_DMC				164
+
+#endif /* __A1_CLKC_H */
-- 
1.9.1


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

* [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-25 11:44 [PATCH 0/2] add Amlogic A1 clock controller driver Jian Hu
  2019-09-25 11:44 ` [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
@ 2019-09-25 11:44 ` Jian Hu
  2019-09-25 13:12   ` Stephen Boyd
  2019-09-25 15:09   ` Jerome Brunet
  1 sibling, 2 replies; 20+ messages in thread
From: Jian Hu @ 2019-09-25 11:44 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jian Hu, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, linux-clk, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

The Amlogic A1 clock includes three parts:
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>
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
---
 arch/arm64/Kconfig.platforms |    1 +
 drivers/clk/meson/Kconfig    |   10 +
 drivers/clk/meson/Makefile   |    1 +
 drivers/clk/meson/a1.c       | 2617 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/meson/a1.h       |  172 +++
 5 files changed, 2801 insertions(+)
 create mode 100644 drivers/clk/meson/a1.c
 create mode 100644 drivers/clk/meson/a1.h

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 16d7614..a48f67d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -138,6 +138,7 @@ config ARCH_MESON
 	select COMMON_CLK_AXG
 	select COMMON_CLK_G12A
 	select MESON_IRQ_GPIO
+	select COMMON_CLK_A1
 	help
 	  This enables support for the arm64 based Amlogic SoCs
 	  such as the s905, S905X/D, S912, A113X/D or S905X/D2
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index dabeb43..e6cb4c3 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -107,3 +107,13 @@ config COMMON_CLK_G12A
 	help
 	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
 	  devices, aka g12a. Say Y if you want peripherals 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.
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 3939f21..6be3a8f 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
+obj-$(CONFIG_COMMON_CLK_A1) += a1.o
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
new file mode 100644
index 0000000..26edae0f
--- /dev/null
+++ b/drivers/clk/meson/a1.c
@@ -0,0 +1,2617 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include "clk-mpll.h"
+#include "clk-pll.h"
+#include "clk-regmap.h"
+#include "vid-pll-div.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_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+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,
+	},
+};
+
+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,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+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,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+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,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+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,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+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,
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+/* fixed pll = 1536M
+ *
+ * fixed pll ----- fclk_div2 = 768M
+ *           |
+ *           ----- fclk_div3 = 512M
+ *           |
+ *           ----- fclk_div5 = 307.2M
+ *           |
+ *           ----- fclk_div7 = 219.4M
+ */
+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_hws = (const struct clk_hw *[]) {
+			&a1_xtal_fixpll.hw
+		},
+		.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,
+		.flags = CLK_IGNORE_UNUSED,
+	},
+};
+
+static const struct pll_params_table a1_hifi_pll_params_table[] = {
+	PLL_PARAMS(128, 5), /* DCO = 614.4M */
+};
+
+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 = 0x10022200 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x00301000 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 10 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL0,	.def = 0x15f11480, .delay_us = 40 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001140 },
+	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001100 },
+};
+
+/*
+ * The Meson A1 HIFI PLL is 614.4M, it requires
+ * a strict register sequence to enable the PLL.
+ * set meson_clk_pcie_pll_ops as its ops
+ */
+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,
+		},
+		.table = a1_hifi_pll_params_table,
+		.init_regs = a1_hifi_init_regs,
+		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "hifi_pll",
+		.ops = &meson_clk_pcie_pll_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_xtal_hifipll.hw
+		},
+		.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,
+		/*
+		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
+		 * or its children clocks.
+		 */
+		.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,
+		/*
+		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
+		 * its children clocks.
+		 */
+		.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,
+		/*
+		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
+		 * its children clocks.
+		 */
+		.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 = 23,
+	},
+	.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,
+		/*
+		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
+		 * or its children clock.
+		 */
+		.flags = CLK_IS_CRITICAL,
+	},
+};
+
+/* sys clk = 64M */
+static u32 mux_table_sys_ab_clk[] = { 0, 1, 2, 3};
+static const struct clk_parent_data sys_ab_clk_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_fclk_div2.hw },
+	{ .hw = &a1_fclk_div3.hw },
+	{ .hw = &a1_fclk_div5.hw },
+};
+
+static struct clk_regmap a1_sys_b_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SYS_CLK_CTRL0,
+		.mask = 0x7,
+		.shift = 26,
+		.table = mux_table_sys_ab_clk,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_b_sel",
+		.ops = &clk_regmap_mux_ro_ops,
+		.parent_data = sys_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
+	},
+};
+
+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,
+		.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,
+		.table = mux_table_sys_ab_clk,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sys_a_sel",
+		.ops = &clk_regmap_mux_ro_ops,
+		.parent_data = sys_ab_clk_parent_data,
+		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
+	},
+};
+
+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,
+		.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,
+	},
+};
+
+/* 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", },
+	{ .hw = &a1_fclk_div2.hw },
+	{ .hw = &a1_fclk_div3.hw },
+	{ .hw = &a1_fclk_div5.hw },
+	{ .hw = &a1_hifi_pll.hw },
+	{ .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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+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_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2.hw
+		},
+		.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 */
+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 },
+	{ .hw = &a1_hifi_pll.hw },
+	{ .hw = &a1_fclk_div2.hw },
+	{ .hw = &a1_fclk_div3.hw },
+	{ .hw = &a1_fclk_div5.hw },
+	{ .hw = &a1_fclk_div7.hw },
+};
+
+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 },
+};
+
+/*
+ * add CLK_IGNORE_UNUSED flag for pwm controller GATE
+ * clk core will disable unused clock, it may disable
+ * vddcore voltage which contrlled by one pwm in bl21.
+ * add the flag to avoid changing cpu voltage.
+ */
+/* 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,
+		.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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* 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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* 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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+static const struct clk_parent_data pwm_ef_parent_data[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a1_sys_clk.hw },
+	{ .hw = &a1_fclk_div5.hw },
+	{ .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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* 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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* spicc clk */
+
+/*    div2   |\         |\       _____
+ *  ---------| |---DIV--| |     |     |    spicc out
+ *  ---------| |        | |-----|GATE |---------
+ *     ..... |/         | /     |_____|
+ *  --------------------|/
+ *                 24M
+ */
+
+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_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2.hw,
+			&a1_fclk_div3.hw,
+			&a1_fclk_div5.hw,
+			&a1_hifi_pll.hw,
+		},
+		.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,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2.hw,
+			&a1_fclk_div3.hw,
+			&a1_fclk_div5.hw,
+			&a1_hifi_pll.hw,
+		},
+		.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 },
+	{ .hw = &a1_fclk_div3.hw },
+	{ .hw = &a1_fclk_div5.hw },
+};
+
+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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+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 | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* sd emmc clk */
+static u32 mux_table_sd_emmc[] = { 0, 1, 2 };
+
+static struct clk_regmap a1_sd_emmc_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = SD_EMMC_CLK_CTRL,
+		.mask = 0x3,
+		.shift = 9,
+		.table = mux_table_sd_emmc,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "sd_emmc_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a1_fclk_div2.hw,
+			&a1_fclk_div3.hw,
+			&a1_fclk_div5.hw,
+		},
+		.num_parents = 3,
+	},
+};
+
+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,
+	},
+};
+
+/* psram clk */
+static const struct clk_hw *psram_parent_hws[] = {
+	&a1_fclk_div2.hw,
+	&a1_fclk_div3.hw,
+	&a1_fclk_div5.hw,
+	&a1_hifi_pll.hw,
+};
+
+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,
+		.parent_hws = psram_parent_hws,
+		.num_parents = ARRAY_SIZE(psram_parent_hws),
+	},
+};
+
+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 const struct clk_hw *dmc_parent_hws[] = {
+	&a1_fclk_div2.hw,
+	&a1_fclk_div3.hw,
+	&a1_fclk_div5.hw,
+	&a1_hifi_pll.hw,
+};
+
+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_hws = dmc_parent_hws,
+		.num_parents = ARRAY_SIZE(dmc_parent_hws),
+	},
+};
+
+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,
+		/*
+		 * add CLK_IGNORE_UNUSED to avoid hangup
+		 * DDR clock should not change at runtime
+		 */
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* 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)
+
+/* CLKTREE_SYS_CLK_EN0 */
+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);
+/* CLKTREE_SYS_CLK_EN1 */
+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);
+/* CLKTREE_AXI_CLK_EN */
+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_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,
+		[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
+ * Peripheral clock register base address is 0xfe000800
+ */
+static struct clk_regmap *const a1_clk_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,
+};
+
+/*
+ * cpu clock register base address is 0xfd000080
+ */
+static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
+	/* TODO */
+};
+
+/*
+ * pll clock register base address is 0xfe007c00
+ */
+static struct clk_regmap *const a1_pll_clk_regmaps[] = {
+	&a1_fixed_pll_dco,
+	&a1_fixed_pll,
+	&a1_hifi_pll,
+	&a1_fclk_div2,
+	&a1_fclk_div3,
+	&a1_fclk_div5,
+	&a1_fclk_div7,
+};
+
+static struct regmap_config clkc_regmap_config = {
+	.reg_bits       = 32,
+	.val_bits       = 32,
+	.reg_stride     = 4,
+};
+
+static struct regmap *a1_regmap_resource(struct device *dev, char *name)
+{
+	struct resource res;
+	void __iomem *base;
+	int i;
+	struct device_node *node = dev->of_node;
+
+	i = of_property_match_string(node, "reg-names", name);
+	if (of_address_to_resource(node, i, &res))
+		return ERR_PTR(-ENOENT);
+
+	base = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(base))
+		return ERR_CAST(base);
+
+	clkc_regmap_config.max_register = resource_size(&res) - 4;
+	clkc_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
+						 "%s-%s", node->name,
+						 name);
+	if (!clkc_regmap_config.name)
+		return ERR_PTR(-ENOMEM);
+
+	return devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
+}
+
+static int a1_clkc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regmap *peripheral_map, *pll_map, *cpu_map;
+	int ret, i;
+
+	/* Get regmap for different clock area */
+	peripheral_map = a1_regmap_resource(dev, "peripheral");
+	if (IS_ERR(peripheral_map)) {
+		dev_err(dev, "peripheral clk registers not found\n");
+		return PTR_ERR(peripheral_map);
+	}
+
+	pll_map = a1_regmap_resource(dev, "pll");
+	if (IS_ERR(pll_map)) {
+		dev_err(dev, "pll clk registers not found\n");
+		return PTR_ERR(pll_map);
+	}
+
+	cpu_map = a1_regmap_resource(dev, "cpu");
+	if (IS_ERR(cpu_map)) {
+		dev_err(dev, "cpu clk registers not found\n");
+		return PTR_ERR(cpu_map);
+	}
+
+	/* Populate regmap for the regmap backed clocks */
+	for (i = 0; i < ARRAY_SIZE(a1_clk_regmaps); i++)
+		a1_clk_regmaps[i]->map = peripheral_map;
+
+	for (i = 0; i < ARRAY_SIZE(a1_cpu_clk_regmaps); i++)
+		a1_cpu_clk_regmaps[i]->map = cpu_map;
+
+	for (i = 0; i < ARRAY_SIZE(a1_pll_clk_regmaps); i++)
+		a1_pll_clk_regmaps[i]->map = pll_map;
+
+	for (i = 0; i < a1_hw_onecell_data.num; i++) {
+		/* array might be sparse */
+		if (!a1_hw_onecell_data.hws[i])
+			continue;
+
+		ret = devm_clk_hw_register(dev, a1_hw_onecell_data.hws[i]);
+		if (ret) {
+			dev_err(dev, "Clock registration failed\n");
+			return ret;
+		}
+	}
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+					   &a1_hw_onecell_data);
+}
+
+static const struct of_device_id clkc_match_table[] = {
+	{ .compatible = "amlogic,a1-clkc" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver a1_driver = {
+	.probe		= a1_clkc_probe,
+	.driver		= {
+		.name	= "a1-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..f2291c4
--- /dev/null
+++ b/drivers/clk/meson/a1.h
@@ -0,0 +1,172 @@
+/* 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 address
+ * APB_BASE:  APB0_BASE_ADDR = 0xfe000800
+ */
+#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
+/*
+ * For PLL register offset
+ * APB_BASE:  APB0_BASE_ADDR = 0xfe007c00
+ */
+#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
+/*
+ * CPU clok register offset
+ * APB_BASE:  APB1_BASE_ADDR = 0xfd000080
+ */
+#define CPUCTRL_CLK_CTRL0		0x00
+#define CPUCTRL_CLK_CTRL1		0x04
+#define CPUCTRL_CLK_CTRL2		0x08
+#define CPUCTRL_CLK_CTRL3		0x0c
+#define CPUCTRL_CLK_CTRL4		0x10
+#define CPUCTRL_CLK_CTRL5		0x14
+#define CPUCTRL_CLK_CTRL6		0x18
+#define CPUCTRL_CLK_CTRL7		0x1c
+
+#define CLKID_FIXED_PLL_DCO		0
+#define CLKID_SYS_A_SEL			10
+#define CLKID_SYS_A_DIV			11
+#define CLKID_SYS_A			12
+#define CLKID_SYS_B_SEL			13
+#define CLKID_SYS_B_DIV			14
+#define CLKID_SYS_B			15
+#define CLKID_XTAL_CLKTREE		18
+#define CLKID_XTAL_FIXPLL		19
+#define CLKID_XTAL_USB_PHY		20
+#define CLKID_XTAL_USB_CTRL		21
+#define CLKID_XTAL_HIFIPLL		22
+#define CLKID_XTAL_SYSPLL		23
+#define CLKID_XTAL_DDS			24
+#define CLKID_DSPA_A_SEL		78
+#define CLKID_DSPA_A_DIV		79
+#define CLKID_DSPA_A			80
+#define CLKID_DSPA_B_SEL		81
+#define CLKID_DSPA_B_DIV		82
+#define CLKID_DSPA_B			83
+#define CLKID_DSPB_A_SEL		85
+#define CLKID_DSPB_A_DIV		86
+#define CLKID_DSPB_A			87
+#define CLKID_DSPB_B_SEL		88
+#define CLKID_DSPB_B_DIV		89
+#define CLKID_DSPB_B			90
+#define CLKID_RTC_32K_CLKIN		96
+#define CLKID_RTC_32K_DIV		97
+#define CLKID_RTC_32K_XTAL		98
+#define CLKID_RTC_32K_SEL		99
+#define CLKID_CECB_32K_CLKIN		106
+#define CLKID_CECB_32K_DIV		107
+#define CLKID_CECB_32K_SEL_PRE		108
+#define CLKID_CECB_32K_SEL		109
+#define CLKID_CECA_32K_CLKIN		101
+#define CLKID_CECA_32K_DIV		102
+#define CLKID_CECA_32K_SEL_PRE		103
+#define CLKID_CECA_32K_SEL		104
+#define CLKID_DIV2_PRE			113
+#define CLKID_24M_DIV2			115
+#define CLKID_GEN_SEL			116
+#define CLKID_GEN_DIV			117
+#define CLKID_SARADC_DIV		120
+#define CLKID_PWM_A_SEL			122
+#define CLKID_PWM_A_DIV			123
+#define CLKID_PWM_B_SEL			125
+#define CLKID_PWM_B_DIV			126
+#define CLKID_PWM_C_SEL			128
+#define CLKID_PWM_C_DIV			129
+#define CLKID_PWM_D_SEL			131
+#define CLKID_PWM_D_DIV			132
+#define CLKID_PWM_E_SEL			134
+#define CLKID_PWM_E_DIV			135
+#define CLKID_PWM_F_SEL			137
+#define CLKID_PWM_F_DIV			138
+#define CLKID_SPICC_SEL			140
+#define CLKID_SPICC_DIV			141
+#define CLKID_SPICC_SEL2		142
+#define CLKID_TS_DIV			144
+#define CLKID_SPIFC_SEL			146
+#define CLKID_SPIFC_DIV			147
+#define CLKID_SPIFC_SEL2		148
+#define CLKID_USB_BUS_SEL		150
+#define CLKID_USB_BUS_DIV		151
+#define CLKID_SD_EMMC_SEL		153
+#define CLKID_SD_EMMC_DIV		154
+#define CLKID_SD_EMMC_SEL2		155
+#define CLKID_PSRAM_SEL			157
+#define CLKID_PSRAM_DIV			158
+#define CLKID_PSRAM_SEL2		159
+#define CLKID_DMC_SEL			161
+#define CLKID_DMC_DIV			162
+#define CLKID_DMC_SEL2			163
+#define NR_CLKS				165
+
+#include <dt-bindings/clock/a1-clkc.h>
+
+#endif /* __A1_H */
-- 
1.9.1


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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-25 11:44 ` [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
@ 2019-09-25 13:12   ` Stephen Boyd
  2019-09-27  3:11     ` Jian Hu
  2019-09-25 15:09   ` Jerome Brunet
  1 sibling, 1 reply; 20+ messages in thread
From: Stephen Boyd @ 2019-09-25 13:12 UTC (permalink / raw)
  To: Jerome Brunet, Jian Hu, Neil Armstrong
  Cc: Rob Herring, Jianxin Pan, devicetree, Martin Blumenstingl,
	Kevin Hilman, Michael Turquette, linux-kernel, Jian Hu,
	Qiufang Dai, linux-amlogic, linux-clk, linux-arm-kernel

Quoting Jian Hu (2019-09-25 04:44:48)
> The Amlogic A1 clock includes three parts:
> 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>
> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>

This second name didn't send the patch. Please follow the signoff
procedures documented in Documentation/process/submitting-patches.rst

> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index 16d7614..a48f67d 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -138,6 +138,7 @@ config ARCH_MESON
>         select COMMON_CLK_AXG
>         select COMMON_CLK_G12A
>         select MESON_IRQ_GPIO
> +       select COMMON_CLK_A1

Sort?

>         help
>           This enables support for the arm64 based Amlogic SoCs
>           such as the s905, S905X/D, S912, A113X/D or S905X/D2
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index dabeb43..e6cb4c3 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>         help
>           Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>           devices, aka g12a. Say Y if you want peripherals to work.
> +
> +config COMMON_CLK_A1

Probably should be placed somewhere alphabetically in this file?

> +       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.
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 3939f21..6be3a8f 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o

I would guess this should be sorted on Kconfig name in this file?

> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
> new file mode 100644
> index 0000000..26edae0f
> --- /dev/null
> +++ b/drivers/clk/meson/a1.c
> @@ -0,0 +1,2617 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/init.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_address.h>
> +#include "clk-mpll.h"
> +#include "clk-pll.h"
> +#include "clk-regmap.h"
> +#include "vid-pll-div.h"
> +#include "clk-dualdiv.h"
> +#include "meson-eeclk.h"
> +#include "a1.h"
> +
[...]
> +
> +/*
> + * The Meson A1 HIFI PLL is 614.4M, it requires
> + * a strict register sequence to enable the PLL.
> + * set meson_clk_pcie_pll_ops as its ops

Please remove this last line as it's obvious from the code what ops are
used.

> + */
> +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,
> +               },
> +               .table = a1_hifi_pll_params_table,
> +               .init_regs = a1_hifi_init_regs,
> +               .init_count = ARRAY_SIZE(a1_hifi_init_regs),
> +       },
> +       .hw.init = &(struct clk_init_data){
> +               .name = "hifi_pll",
> +               .ops = &meson_clk_pcie_pll_ops,
> +               .parent_hws = (const struct clk_hw *[]) {
> +                       &a1_xtal_hifipll.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,
> +               /*
> +                * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
> +                * or its children clocks.

This comment is useless. Please replace it with an actual reason for
keeping the clk on instead of describing what the flag does.

> +                */
> +               .flags = CLK_IS_CRITICAL,
> +       },
> +};
> +
[..]
> +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,
> +               /*
> +                * add CLK_IGNORE_UNUSED to avoid hangup
> +                * DDR clock should not change at runtime
> +                */
> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,

So not CLK_IS_CRITICAL?

> +       },
> +};
> +
[...]
> +
> +/*
> + * cpu clock register base address is 0xfd000080
> + */
> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
> +       /* TODO */

Can it be done?

> +};

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

* Re: [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-09-25 11:44 ` [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
@ 2019-09-25 14:29   ` Jerome Brunet
  2019-09-27  6:08     ` Jian Hu
  2019-09-27 20:10   ` Rob Herring
  1 sibling, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-09-25 14:29 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Jian Hu, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, linux-clk, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:

In addition to the comment expressed by Stephen on patch 2

> Add the documentation to support Amlogic A1 clock driver,
> and add A1 clock controller bindings.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> ---
>  .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  65 +++++++++++++
>  include/dt-bindings/clock/a1-clkc.h                | 102 +++++++++++++++++++++
>  2 files changed, 167 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/a1-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..f012eb2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> @@ -0,0 +1,65 @@
> +/* 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 A1 Clock Control Unit Device Tree Bindings
> +
> +maintainers:
> +  - Neil Armstrong <narmstrong@baylibre.com>
> +  - Jerome Brunet <jbrunet@baylibre.com>
> +  - Jian Hu <jian.hu@jian.hu.com>
> +
> +properties:
> +  compatible:
> +    - enum:
> +        - amlogic,a1-clkc
> +
> +  reg:
> +    minItems: 1
> +    maxItems: 3
> +    items:
> +      - description: peripheral registers
> +      - description: cpu registers
> +      - description: pll registers
> +
> +  reg-names:
> +    items:
> +      - const: peripheral
> +      - const: pll
> +      - const: cpu
> +
> +  clocks:
> +    maxItems: 1
> +    items:
> +      - description: Input Oscillator (usually at 24MHz)
> +
> +  clock-names:
> +    maxItems: 1
> +    items:
> +      - const: xtal
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - clocks
> +  - clock-names
> +  - "#clock-cells"
> +
> +examples:
> +  - |
> +    clkc: clock-controller {
> +        compatible = "amlogic,a1-clkc";
> +        reg = <0x0 0xfe000800 0x0 0x100>,
> +              <0x0 0xfe007c00 0x0 0x21c>,
> +              <0x0 0xfd000080 0x0 0x20>;
> +        reg-names = "peripheral", "pll", "cpu";

I'm sorry but I don't agree with this. You are trying to regroup several
controllers into one with this, and it is not OK

By the looks of it there are 3 different controllers, including one you
did not implement in the driver.

> +        clocks = <&xtal;
> +        clock-names = "xtal";
> +        #clock-cells = <1>;

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-25 11:44 ` [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
  2019-09-25 13:12   ` Stephen Boyd
@ 2019-09-25 15:09   ` Jerome Brunet
  2019-09-27  9:52     ` Jian Hu
  1 sibling, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-09-25 15:09 UTC (permalink / raw)
  To: Jian Hu, Neil Armstrong
  Cc: Jian Hu, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, linux-clk, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:

> The Amlogic A1 clock includes three parts:
> 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>
> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> ---
>  arch/arm64/Kconfig.platforms |    1 +
>  drivers/clk/meson/Kconfig    |   10 +
>  drivers/clk/meson/Makefile   |    1 +
>  drivers/clk/meson/a1.c       | 2617 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/meson/a1.h       |  172 +++
>  5 files changed, 2801 insertions(+)
>  create mode 100644 drivers/clk/meson/a1.c
>  create mode 100644 drivers/clk/meson/a1.h
>
> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index 16d7614..a48f67d 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -138,6 +138,7 @@ config ARCH_MESON
>  	select COMMON_CLK_AXG
>  	select COMMON_CLK_G12A
>  	select MESON_IRQ_GPIO
> +	select COMMON_CLK_A1

This need to be separate patch addressed to Kevin once your driver is merged

>  	help
>  	  This enables support for the arm64 based Amlogic SoCs
>  	  such as the s905, S905X/D, S912, A113X/D or S905X/D2
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index dabeb43..e6cb4c3 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>  	help
>  	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>  	  devices, aka g12a. Say Y if you want peripherals 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.
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 3939f21..6be3a8f 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
> new file mode 100644
> index 0000000..26edae0f
> --- /dev/null
> +++ b/drivers/clk/meson/a1.c
> @@ -0,0 +1,2617 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/init.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_address.h>
> +#include "clk-mpll.h"
> +#include "clk-pll.h"
> +#include "clk-regmap.h"
> +#include "vid-pll-div.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_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +		.flags = CLK_IS_CRITICAL,

Is CCF even expected to touch this ever ? what about RO ops ?
Please review your other clocks with this in mind

> +	},
> +};
> +
> +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,
> +	},
> +};
> +
> +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,
> +		.flags = CLK_IS_CRITICAL,

How is an USB clock critical to the system ?
Please review your other clocks with comment in mind ...

> +	},
> +};
> +
> +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,
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +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,
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +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,
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +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,
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +/* fixed pll = 1536M
> + *
> + * fixed pll ----- fclk_div2 = 768M
> + *           |
> + *           ----- fclk_div3 = 512M
> + *           |
> + *           ----- fclk_div5 = 307.2M
> + *           |
> + *           ----- fclk_div7 = 219.4M
> + */

The framework will make those calculation ... you can remove this

> +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_hws = (const struct clk_hw *[]) {
> +			&a1_xtal_fixpll.hw
> +		},
> +		.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,
> +		.flags = CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
> +	PLL_PARAMS(128, 5), /* DCO = 614.4M */
> +};
> +
> +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 = 0x10022200 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x00301000 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 10 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL0,	.def = 0x15f11480, .delay_us = 40 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001140 },
> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001100 },
> +};
> +
> +/*
> + * The Meson A1 HIFI PLL is 614.4M, it requires
> + * a strict register sequence to enable the PLL.
> + * set meson_clk_pcie_pll_ops as its ops
> + */

Could you elaborate on this ? What need to be done to enable the clock ?
Also the HIFI PLL used to be able to do a *LOT* of different rate which
might be desirable for audio use case. Why is this one restricted to one
particular rate ?

> +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,
> +		},
> +		.table = a1_hifi_pll_params_table,
> +		.init_regs = a1_hifi_init_regs,
> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "hifi_pll",
> +		.ops = &meson_clk_pcie_pll_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_xtal_hifipll.hw
> +		},
> +		.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,
> +		/*
> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
> +		 * or its children clocks.
> +		 */

The meaning of this flag is already documented in clk-provider.h
The reason why you need this flag is lot more interesting here ...

Same below 

> +		.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,
> +		/*
> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
> +		 * its children clocks.
> +		 */
> +		.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,
> +		/*
> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
> +		 * its children clocks.
> +		 */
> +		.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 = 23,
> +	},
> +	.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,
> +		/*
> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
> +		 * or its children clock.
> +		 */
> +		.flags = CLK_IS_CRITICAL,
> +	},
> +};
> +
> +/* sys clk = 64M */

Again this comment does not help understanding the driver code, please
remove

> +static u32 mux_table_sys_ab_clk[] = { 0, 1, 2, 3};

This table is useless

> +static const struct clk_parent_data sys_ab_clk_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_fclk_div2.hw },
> +	{ .hw = &a1_fclk_div3.hw },
> +	{ .hw = &a1_fclk_div5.hw },
> +};
> +
> +static struct clk_regmap a1_sys_b_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 26,
> +		.table = mux_table_sys_ab_clk,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_b_sel",
> +		.ops = &clk_regmap_mux_ro_ops,
> +		.parent_data = sys_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
> +	},
> +};
> +
> +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,
> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,

Why does this need to be critical ?
The a1_sys_clk (leaf of the block) could possibly be critical (if you
explain why) ... but the flag should not be needed in the middle of the
block

> +	},
> +};
> +
> +static struct clk_regmap a1_sys_a_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SYS_CLK_CTRL0,
> +		.mask = 0x7,
> +		.shift = 10,
> +		.table = mux_table_sys_ab_clk,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sys_a_sel",
> +		.ops = &clk_regmap_mux_ro_ops,
> +		.parent_data = sys_ab_clk_parent_data,
> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
> +	},
> +};
> +
> +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,
> +		.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,

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 };

useless

> +
> +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", },
> +	{ .hw = &a1_fclk_div2.hw },
> +	{ .hw = &a1_fclk_div3.hw },
> +	{ .hw = &a1_fclk_div5.hw },
> +	{ .hw = &a1_hifi_pll.hw },
> +	{ .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 | CLK_IGNORE_UNUSED,

This CLK_IGNORE_UNUSED, if justified, needs to be explained

> +	},
> +};
> +
> +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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +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_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2.hw
> +		},
> +		.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 */

Either put something helpful or don't put anything
For example explaining why there is a hole in the table bellow and what
is parent 4 (if any) would be helpful.

> +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 },
> +	{ .hw = &a1_hifi_pll.hw },
> +	{ .hw = &a1_fclk_div2.hw },
> +	{ .hw = &a1_fclk_div3.hw },
> +	{ .hw = &a1_fclk_div5.hw },
> +	{ .hw = &a1_fclk_div7.hw },
> +};
> +
> +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 },
> +};
> +
> +/*
> + * add CLK_IGNORE_UNUSED flag for pwm controller GATE
> + * clk core will disable unused clock, it may disable
> + * vddcore voltage which contrlled by one pwm in bl21.
                             ^
                             typo

> + * add the flag to avoid changing cpu voltage.

80 char per line is ok
This comment would be better placed next to the corresponding flag

Also you could explain that flag could be removed when CCF has some
hand-off mechanism (similar comments you can copy in other driver)

> + */
> +/* 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,
> +		.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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* 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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* 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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +static const struct clk_parent_data pwm_ef_parent_data[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a1_sys_clk.hw },
> +	{ .hw = &a1_fclk_div5.hw },
> +	{ .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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* 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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* spicc clk */
> +
> +/*    div2   |\         |\       _____
> + *  ---------| |---DIV--| |     |     |    spicc out
> + *  ---------| |        | |-----|GATE |---------
> + *     ..... |/         | /     |_____|
> + *  --------------------|/
> + *                 24M
> + */
> +
> +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_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2.hw,
> +			&a1_fclk_div3.hw,
> +			&a1_fclk_div5.hw,
> +			&a1_hifi_pll.hw,
> +		},
> +		.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,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2.hw,
> +			&a1_fclk_div3.hw,
> +			&a1_fclk_div5.hw,
> +			&a1_hifi_pll.hw,
> +		},
> +		.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 },
> +	{ .hw = &a1_fclk_div3.hw },
> +	{ .hw = &a1_fclk_div5.hw },
> +};
> +
> +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 | CLK_IGNORE_UNUSED,

Again, every unused flag need to be properly explained

> +	},
> +};
> +
> +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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +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 | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* sd emmc clk */
> +static u32 mux_table_sd_emmc[] = { 0, 1, 2 };
> +
> +static struct clk_regmap a1_sd_emmc_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = SD_EMMC_CLK_CTRL,
> +		.mask = 0x3,
> +		.shift = 9,
> +		.table = mux_table_sd_emmc,
> +	},
> +	.hw.init = &(struct clk_init_data){
> +		.name = "sd_emmc_sel",
> +		.ops = &clk_regmap_mux_ops,
> +		.parent_hws = (const struct clk_hw *[]) {
> +			&a1_fclk_div2.hw,
> +			&a1_fclk_div3.hw,
> +			&a1_fclk_div5.hw,
> +		},
> +		.num_parents = 3,
> +	},
> +};
> +
> +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,
> +	},
> +};
> +
> +/* psram clk */
> +static const struct clk_hw *psram_parent_hws[] = {
> +	&a1_fclk_div2.hw,
> +	&a1_fclk_div3.hw,
> +	&a1_fclk_div5.hw,
> +	&a1_hifi_pll.hw,
> +};
> +
> +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,
> +		.parent_hws = psram_parent_hws,
> +		.num_parents = ARRAY_SIZE(psram_parent_hws),
> +	},
> +};
> +
> +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 const struct clk_hw *dmc_parent_hws[] = {
> +	&a1_fclk_div2.hw,
> +	&a1_fclk_div3.hw,
> +	&a1_fclk_div5.hw,
> +	&a1_hifi_pll.hw,
> +};
> +
> +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_hws = dmc_parent_hws,
> +		.num_parents = ARRAY_SIZE(dmc_parent_hws),
> +	},
> +};
> +
> +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,
> +		/*
> +		 * add CLK_IGNORE_UNUSED to avoid hangup
> +		 * DDR clock should not change at runtime
> +		 */

CRITICAL ? RO ops maybe ?

> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> +	},
> +};
> +
> +/* 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)
> +
> +/* CLKTREE_SYS_CLK_EN0 */

Full caps is not ok ... and once again, try to add comment which helps

> +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);
> +/* CLKTREE_SYS_CLK_EN1 */
> +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);
> +/* CLKTREE_AXI_CLK_EN */
> +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_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,
> +		[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
> + * Peripheral clock register base address is 0xfe000800

this info will be in DT

> + */
> +static struct clk_regmap *const a1_clk_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,
> +};
> +
> +/*
> + * cpu clock register base address is 0xfd000080
> + */
> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
> +	/* TODO */
> +};
> +
> +/*
> + * pll clock register base address is 0xfe007c00
> + */
> +static struct clk_regmap *const a1_pll_clk_regmaps[] = {
> +	&a1_fixed_pll_dco,
> +	&a1_fixed_pll,
> +	&a1_hifi_pll,
> +	&a1_fclk_div2,
> +	&a1_fclk_div3,
> +	&a1_fclk_div5,
> +	&a1_fclk_div7,
> +};
> +
> +static struct regmap_config clkc_regmap_config = {
> +	.reg_bits       = 32,
> +	.val_bits       = 32,
> +	.reg_stride     = 4,
> +};
> +
> +static struct regmap *a1_regmap_resource(struct device *dev, char *name)
> +{
> +	struct resource res;
> +	void __iomem *base;
> +	int i;
> +	struct device_node *node = dev->of_node;
> +
> +	i = of_property_match_string(node, "reg-names", name);
> +	if (of_address_to_resource(node, i, &res))
> +		return ERR_PTR(-ENOENT);
> +
> +	base = devm_ioremap_resource(dev, &res);
> +	if (IS_ERR(base))
> +		return ERR_CAST(base);
> +
> +	clkc_regmap_config.max_register = resource_size(&res) - 4;
> +	clkc_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
> +						 "%s-%s", node->name,
> +						 name);
> +	if (!clkc_regmap_config.name)
> +		return ERR_PTR(-ENOMEM);
> +
> +	return devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
> +}
> +
> +static int a1_clkc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regmap *peripheral_map, *pll_map, *cpu_map;
> +	int ret, i;
> +
> +	/* Get regmap for different clock area */
> +	peripheral_map = a1_regmap_resource(dev, "peripheral");
> +	if (IS_ERR(peripheral_map)) {
> +		dev_err(dev, "peripheral clk registers not found\n");
> +		return PTR_ERR(peripheral_map);
> +	}
> +
> +	pll_map = a1_regmap_resource(dev, "pll");
> +	if (IS_ERR(pll_map)) {
> +		dev_err(dev, "pll clk registers not found\n");
> +		return PTR_ERR(pll_map);
> +	}
> +
> +	cpu_map = a1_regmap_resource(dev, "cpu");
> +	if (IS_ERR(cpu_map)) {
> +		dev_err(dev, "cpu clk registers not found\n");
> +		return PTR_ERR(cpu_map);
> +	}
> +
> +	/* Populate regmap for the regmap backed clocks */
> +	for (i = 0; i < ARRAY_SIZE(a1_clk_regmaps); i++)
> +		a1_clk_regmaps[i]->map = peripheral_map;
> +
> +	for (i = 0; i < ARRAY_SIZE(a1_cpu_clk_regmaps); i++)
> +		a1_cpu_clk_regmaps[i]->map = cpu_map;
> +
> +	for (i = 0; i < ARRAY_SIZE(a1_pll_clk_regmaps); i++)
> +		a1_pll_clk_regmaps[i]->map = pll_map;

Unless you have a rock solid reason why you absolutely need to make
single controller out of this 3 regions, Nack.

> +
> +	for (i = 0; i < a1_hw_onecell_data.num; i++) {
> +		/* array might be sparse */
> +		if (!a1_hw_onecell_data.hws[i])
> +			continue;
> +
> +		ret = devm_clk_hw_register(dev, a1_hw_onecell_data.hws[i]);
> +		if (ret) {
> +			dev_err(dev, "Clock registration failed\n");
> +			return ret;
> +		}
> +	}
> +
> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> +					   &a1_hw_onecell_data);
> +}
> +
> +static const struct of_device_id clkc_match_table[] = {
> +	{ .compatible = "amlogic,a1-clkc" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver a1_driver = {
> +	.probe		= a1_clkc_probe,
> +	.driver		= {
> +		.name	= "a1-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..f2291c4
> --- /dev/null
> +++ b/drivers/clk/meson/a1.h
> @@ -0,0 +1,172 @@
> +/* 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 address
> + * APB_BASE:  APB0_BASE_ADDR = 0xfe000800

Again this info is DT and might become wrong if your controller is ever
compatible with another SoC

> + */
> +#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
> +/*
> + * For PLL register offset
> + * APB_BASE:  APB0_BASE_ADDR = 0xfe007c00
> + */
> +#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
> +/*
> + * CPU clok register offset
> + * APB_BASE:  APB1_BASE_ADDR = 0xfd000080
> + */
> +#define CPUCTRL_CLK_CTRL0		0x00
> +#define CPUCTRL_CLK_CTRL1		0x04
> +#define CPUCTRL_CLK_CTRL2		0x08
> +#define CPUCTRL_CLK_CTRL3		0x0c
> +#define CPUCTRL_CLK_CTRL4		0x10
> +#define CPUCTRL_CLK_CTRL5		0x14
> +#define CPUCTRL_CLK_CTRL6		0x18
> +#define CPUCTRL_CLK_CTRL7		0x1c
> +
> +#define CLKID_FIXED_PLL_DCO		0
> +#define CLKID_SYS_A_SEL			10
> +#define CLKID_SYS_A_DIV			11
> +#define CLKID_SYS_A			12
> +#define CLKID_SYS_B_SEL			13
> +#define CLKID_SYS_B_DIV			14
> +#define CLKID_SYS_B			15
> +#define CLKID_XTAL_CLKTREE		18
> +#define CLKID_XTAL_FIXPLL		19
> +#define CLKID_XTAL_USB_PHY		20
> +#define CLKID_XTAL_USB_CTRL		21
> +#define CLKID_XTAL_HIFIPLL		22
> +#define CLKID_XTAL_SYSPLL		23
> +#define CLKID_XTAL_DDS			24
> +#define CLKID_DSPA_A_SEL		78
> +#define CLKID_DSPA_A_DIV		79
> +#define CLKID_DSPA_A			80
> +#define CLKID_DSPA_B_SEL		81
> +#define CLKID_DSPA_B_DIV		82
> +#define CLKID_DSPA_B			83
> +#define CLKID_DSPB_A_SEL		85
> +#define CLKID_DSPB_A_DIV		86
> +#define CLKID_DSPB_A			87
> +#define CLKID_DSPB_B_SEL		88
> +#define CLKID_DSPB_B_DIV		89
> +#define CLKID_DSPB_B			90
> +#define CLKID_RTC_32K_CLKIN		96
> +#define CLKID_RTC_32K_DIV		97
> +#define CLKID_RTC_32K_XTAL		98
> +#define CLKID_RTC_32K_SEL		99
> +#define CLKID_CECB_32K_CLKIN		106
> +#define CLKID_CECB_32K_DIV		107
> +#define CLKID_CECB_32K_SEL_PRE		108
> +#define CLKID_CECB_32K_SEL		109
> +#define CLKID_CECA_32K_CLKIN		101
> +#define CLKID_CECA_32K_DIV		102
> +#define CLKID_CECA_32K_SEL_PRE		103
> +#define CLKID_CECA_32K_SEL		104
> +#define CLKID_DIV2_PRE			113
> +#define CLKID_24M_DIV2			115
> +#define CLKID_GEN_SEL			116
> +#define CLKID_GEN_DIV			117
> +#define CLKID_SARADC_DIV		120
> +#define CLKID_PWM_A_SEL			122
> +#define CLKID_PWM_A_DIV			123
> +#define CLKID_PWM_B_SEL			125
> +#define CLKID_PWM_B_DIV			126
> +#define CLKID_PWM_C_SEL			128
> +#define CLKID_PWM_C_DIV			129
> +#define CLKID_PWM_D_SEL			131
> +#define CLKID_PWM_D_DIV			132
> +#define CLKID_PWM_E_SEL			134
> +#define CLKID_PWM_E_DIV			135
> +#define CLKID_PWM_F_SEL			137
> +#define CLKID_PWM_F_DIV			138
> +#define CLKID_SPICC_SEL			140
> +#define CLKID_SPICC_DIV			141
> +#define CLKID_SPICC_SEL2		142
> +#define CLKID_TS_DIV			144
> +#define CLKID_SPIFC_SEL			146
> +#define CLKID_SPIFC_DIV			147
> +#define CLKID_SPIFC_SEL2		148
> +#define CLKID_USB_BUS_SEL		150
> +#define CLKID_USB_BUS_DIV		151
> +#define CLKID_SD_EMMC_SEL		153
> +#define CLKID_SD_EMMC_DIV		154
> +#define CLKID_SD_EMMC_SEL2		155
> +#define CLKID_PSRAM_SEL			157
> +#define CLKID_PSRAM_DIV			158
> +#define CLKID_PSRAM_SEL2		159
> +#define CLKID_DMC_SEL			161
> +#define CLKID_DMC_DIV			162
> +#define CLKID_DMC_SEL2			163
> +#define NR_CLKS				165
> +
> +#include <dt-bindings/clock/a1-clkc.h>
> +
> +#endif /* __A1_H */
> -- 
> 1.9.1

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

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

Hi, Stephen

Thank you for review

On 2019/9/25 21:12, Stephen Boyd wrote:
> Quoting Jian Hu (2019-09-25 04:44:48)
>> The Amlogic A1 clock includes three parts:
>> 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>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> 
> This second name didn't send the patch. Please follow the signoff
> procedures documented in Documentation/process/submitting-patches.rst
> 
>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>> index 16d7614..a48f67d 100644
>> --- a/arch/arm64/Kconfig.platforms
>> +++ b/arch/arm64/Kconfig.platforms
>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>          select COMMON_CLK_AXG
>>          select COMMON_CLK_G12A
>>          select MESON_IRQ_GPIO
>> +       select COMMON_CLK_A1
> 
> Sort?
ok, I will put it behind COMMON_CLK_AXG
> 
>>          help
>>            This enables support for the arm64 based Amlogic SoCs
>>            such as the s905, S905X/D, S912, A113X/D or S905X/D2
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index dabeb43..e6cb4c3 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>          help
>>            Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>            devices, aka g12a. Say Y if you want peripherals to work.
>> +
>> +config COMMON_CLK_A1
> 
> Probably should be placed somewhere alphabetically in this file?
ok, I will put it behind COMMON_CLK_AXG_AUDIO
> 
>> +       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.
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 3939f21..6be3a8f 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
> 
> I would guess this should be sorted on Kconfig name in this file?
ok, I will put it behind COMMON_CLK_AXG_AUDIO
> 
>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>> new file mode 100644
>> index 0000000..26edae0f
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1.c
>> @@ -0,0 +1,2617 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/init.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/of_address.h>
>> +#include "clk-mpll.h"
>> +#include "clk-pll.h"
>> +#include "clk-regmap.h"
>> +#include "vid-pll-div.h"
>> +#include "clk-dualdiv.h"
>> +#include "meson-eeclk.h"
>> +#include "a1.h"
>> +
> [...]
>> +
>> +/*
>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>> + * a strict register sequence to enable the PLL.
>> + * set meson_clk_pcie_pll_ops as its ops
> 
> Please remove this last line as it's obvious from the code what ops are
> used.
> 
ok, I will remove it.
>> + */
>> +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,
>> +               },
>> +               .table = a1_hifi_pll_params_table,
>> +               .init_regs = a1_hifi_init_regs,
>> +               .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>> +       },
>> +       .hw.init = &(struct clk_init_data){
>> +               .name = "hifi_pll",
>> +               .ops = &meson_clk_pcie_pll_ops,
>> +               .parent_hws = (const struct clk_hw *[]) {
>> +                       &a1_xtal_hifipll.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,
>> +               /*
>> +                * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>> +                * or its children clocks.
> 
> This comment is useless. Please replace it with an actual reason for
> keeping the clk on instead of describing what the flag does.
> 
ok, The actual reason is it should not change at runtime.
>> +                */
>> +               .flags = CLK_IS_CRITICAL,
>> +       },
>> +};
>> +
> [..]
>> +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,
>> +               /*
>> +                * add CLK_IGNORE_UNUSED to avoid hangup
>> +                * DDR clock should not change at runtime
>> +                */
>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> 
> So not CLK_IS_CRITICAL?
Yes, CLK_IS_CRITICAL is better, I will change it.
> 
>> +       },
>> +};
>> +
> [...]
>> +
>> +/*
>> + * cpu clock register base address is 0xfd000080
>> + */
>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>> +       /* TODO */
> 
> Can it be done?
I plan to compelte cpu clock with the DVFS verified. And  Some 
peripheral devices rely on this patch to send. I prefer to do it in the 
next patch.
> 
>> +};
> 
> .
> 

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

* Re: [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-09-25 14:29   ` Jerome Brunet
@ 2019-09-27  6:08     ` Jian Hu
  0 siblings, 0 replies; 20+ messages in thread
From: Jian Hu @ 2019-09-27  6:08 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jianxin Pan, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, linux-clk,
	linux-amlogic, linux-arm-kernel, linux-kernel, devicetree

Hi, Jerome

Thank you for review.

On 2019/9/25 22:29, Jerome Brunet wrote:
> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
> 
> In addition to the comment expressed by Stephen on patch 2
> 
got it.
>> Add the documentation to support Amlogic A1 clock driver,
>> and add A1 clock controller bindings.
>>
>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>> ---
>>   .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  65 +++++++++++++
>>   include/dt-bindings/clock/a1-clkc.h                | 102 +++++++++++++++++++++
>>   2 files changed, 167 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>>   create mode 100644 include/dt-bindings/clock/a1-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..f012eb2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>> @@ -0,0 +1,65 @@
>> +/* 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 A1 Clock Control Unit Device Tree Bindings
>> +
>> +maintainers:
>> +  - Neil Armstrong <narmstrong@baylibre.com>
>> +  - Jerome Brunet <jbrunet@baylibre.com>
>> +  - Jian Hu <jian.hu@jian.hu.com>
>> +
>> +properties:
>> +  compatible:
>> +    - enum:
>> +        - amlogic,a1-clkc
>> +
>> +  reg:
>> +    minItems: 1
>> +    maxItems: 3
>> +    items:
>> +      - description: peripheral registers
>> +      - description: cpu registers
>> +      - description: pll registers
>> +
>> +  reg-names:
>> +    items:
>> +      - const: peripheral
>> +      - const: pll
>> +      - const: cpu
>> +
>> +  clocks:
>> +    maxItems: 1
>> +    items:
>> +      - description: Input Oscillator (usually at 24MHz)
>> +
>> +  clock-names:
>> +    maxItems: 1
>> +    items:
>> +      - const: xtal
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - reg-names
>> +  - clocks
>> +  - clock-names
>> +  - "#clock-cells"
>> +
>> +examples:
>> +  - |
>> +    clkc: clock-controller {
>> +        compatible = "amlogic,a1-clkc";
>> +        reg = <0x0 0xfe000800 0x0 0x100>,
>> +              <0x0 0xfe007c00 0x0 0x21c>,
>> +              <0x0 0xfd000080 0x0 0x20>;
>> +        reg-names = "peripheral", "pll", "cpu";
> 
> I'm sorry but I don't agree with this. You are trying to regroup several
> controllers into one with this, and it is not OK
> 
> By the looks of it there are 3 different controllers, including one you
> did not implement in the driver.
> 
Yes, In A1, the clock registers include three regions.

I agree with your opinion. I will implement the two clock drivers of 
peripheral and plls first in PATCH V2. And CPU clock driver will be sent 
after the patches are merged.

>> +        clocks = <&xtal;
>> +        clock-names = "xtal";
>> +        #clock-cells = <1>;
> 
> .
> 

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-25 15:09   ` Jerome Brunet
@ 2019-09-27  9:52     ` Jian Hu
  2019-09-27 13:32       ` Jerome Brunet
  0 siblings, 1 reply; 20+ messages in thread
From: Jian Hu @ 2019-09-27  9:52 UTC (permalink / raw)
  To: Jerome Brunet, Neil Armstrong
  Cc: Jianxin Pan, Kevin Hilman, Rob Herring, Martin Blumenstingl,
	Michael Turquette, Stephen Boyd, Qiufang Dai, linux-clk,
	linux-amlogic, linux-arm-kernel, linux-kernel, devicetree

Hi, Jerome

Thank you for review.

On 2019/9/25 23:09, Jerome Brunet wrote:
> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> The Amlogic A1 clock includes three parts:
>> 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>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>> ---
>>   arch/arm64/Kconfig.platforms |    1 +
>>   drivers/clk/meson/Kconfig    |   10 +
>>   drivers/clk/meson/Makefile   |    1 +
>>   drivers/clk/meson/a1.c       | 2617 ++++++++++++++++++++++++++++++++++++++++++
>>   drivers/clk/meson/a1.h       |  172 +++
>>   5 files changed, 2801 insertions(+)
>>   create mode 100644 drivers/clk/meson/a1.c
>>   create mode 100644 drivers/clk/meson/a1.h
>>
>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>> index 16d7614..a48f67d 100644
>> --- a/arch/arm64/Kconfig.platforms
>> +++ b/arch/arm64/Kconfig.platforms
>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>   	select COMMON_CLK_AXG
>>   	select COMMON_CLK_G12A
>>   	select MESON_IRQ_GPIO
>> +	select COMMON_CLK_A1
> 
> This need to be separate patch addressed to Kevin once your driver is merged
> 
ok, I will remove it in PATCH V2. And send it again after the driver is 
merged.
>>   	help
>>   	  This enables support for the arm64 based Amlogic SoCs
>>   	  such as the s905, S905X/D, S912, A113X/D or S905X/D2
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index dabeb43..e6cb4c3 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>   	help
>>   	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>   	  devices, aka g12a. Say Y if you want peripherals 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.
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 3939f21..6be3a8f 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>> new file mode 100644
>> index 0000000..26edae0f
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1.c
>> @@ -0,0 +1,2617 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +/*
>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/init.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/of_address.h>
>> +#include "clk-mpll.h"
>> +#include "clk-pll.h"
>> +#include "clk-regmap.h"
>> +#include "vid-pll-div.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_ops,
>> +		.parent_data = &(const struct clk_parent_data) {
>> +			.fw_name = "xtal",
>> +		},
>> +		.num_parents = 1,
>> +		.flags = CLK_IS_CRITICAL,
> 
> Is CCF even expected to touch this ever ? what about RO ops ?
> Please review your other clocks with this in mind
> 
the clock should not be changed at runtime.clk_regmap_gate_ro_ops
is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>> +	},
>> +};
>> +
>> +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,
>> +	},
>> +};
>> +
>> +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,
>> +		.flags = CLK_IS_CRITICAL,
> 
> How is an USB clock critical to the system ?
> Please review your other clocks with comment in mind ...
the usb clock does not affect the system,
remove the CLK_IS_CRITICAL flag
> 
>> +	},
>> +};
>> +
>> +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,
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
the usb clock does not affect the system,
remove the CLK_IS_CRITICAL flag
>> +
>> +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,
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
CLK_IS_CRITICAL is need to lock hifi pll.
>> +
>> +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,
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
>> +
when CPU clock is at fixed clock, sys pll
will be disabled, xtal_syspll will be disabled too.
when setting sys pll, call clk_set_rate to lock
sys pll, add RO ops to avoid disabling the clock

>> +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,
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
CLK_IS_CRITICAL is need to lock dds
>> +
>> +/* fixed pll = 1536M
>> + *
>> + * fixed pll ----- fclk_div2 = 768M
>> + *           |
>> + *           ----- fclk_div3 = 512M
>> + *           |
>> + *           ----- fclk_div5 = 307.2M
>> + *           |
>> + *           ----- fclk_div7 = 219.4M
>> + */
> 
> The framework will make those calculation ... you can remove this
> 
ok, I will remote the comment.
>> +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_hws = (const struct clk_hw *[]) {
>> +			&a1_xtal_fixpll.hw
>> +		},
>> +		.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,
>> +		.flags = CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>> +	PLL_PARAMS(128, 5), /* DCO = 614.4M */
>> +};
>> +
>> +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 = 0x10022200 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x00301000 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 10 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0,	.def = 0x15f11480, .delay_us = 40 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001140 },
>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001100 },
>> +};
>> +
>> +/*
>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>> + * a strict register sequence to enable the PLL.
>> + * set meson_clk_pcie_pll_ops as its ops
>> + */
> 
> Could you elaborate on this ? What need to be done to enable the clock ?
> Also the HIFI PLL used to be able to do a *LOT* of different rate which
> might be desirable for audio use case. Why is this one restricted to one
> particular rate ?
> 
The audio working frequency are 44.1khz, 48khz and 192khz.

614.4M can meet the three frequency.

after the hifi pll, there are two dividers in Audio clock.

614.4M/3200 = 192khz

614.4M/12800 = 48khz

614,4M/13932 = 44.0999khz

>> +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,
>> +		},
>> +		.table = a1_hifi_pll_params_table,
>> +		.init_regs = a1_hifi_init_regs,
>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "hifi_pll",
>> +		.ops = &meson_clk_pcie_pll_ops,
>> +		.parent_hws = (const struct clk_hw *[]) {
>> +			&a1_xtal_hifipll.hw
>> +		},
>> +		.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,
>> +		/*
>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>> +		 * or its children clocks.
>> +		 */
> 
> The meaning of this flag is already documented in clk-provider.h
> The reason why you need this flag is lot more interesting here ...
> 
> Same below
ok, I will replace new comments here.
> 
>> +		.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,
>> +		/*
>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>> +		 * its children clocks.
>> +		 */
>> +		.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,
>> +		/*
>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>> +		 * its children clocks.
>> +		 */
>> +		.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 = 23,
>> +	},
>> +	.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,
>> +		/*
>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>> +		 * or its children clock.
>> +		 */
>> +		.flags = CLK_IS_CRITICAL,
>> +	},
>> +};
>> +
>> +/* sys clk = 64M */
> 
> Again this comment does not help understanding the driver code, please
> remove
> 
got it.
>> +static u32 mux_table_sys_ab_clk[] = { 0, 1, 2, 3};
> 
> This table is useless
> 
>> +static const struct clk_parent_data sys_ab_clk_parent_data[] = {
>> +	{ .fw_name = "xtal", },
>> +	{ .hw = &a1_fclk_div2.hw },
>> +	{ .hw = &a1_fclk_div3.hw },
>> +	{ .hw = &a1_fclk_div5.hw },
>> +};
>> +
>> +static struct clk_regmap a1_sys_b_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = SYS_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 26,
>> +		.table = mux_table_sys_ab_clk,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "sys_b_sel",
>> +		.ops = &clk_regmap_mux_ro_ops,
>> +		.parent_data = sys_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>> +	},
>> +};
>> +
>> +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,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> 
> Why does this need to be critical ?
> The a1_sys_clk (leaf of the block) could possibly be critical (if you
> explain why) ... but the flag should not be needed in the middle of the
> block
> 
ok, the a1_sys_clk should not be changed at runtime, it is the same with 
the clk81 clock in G12A. Just use another name in A1.
>> +	},
>> +};
>> +
>> +static struct clk_regmap a1_sys_a_sel = {
>> +	.data = &(struct clk_regmap_mux_data){
>> +		.offset = SYS_CLK_CTRL0,
>> +		.mask = 0x7,
>> +		.shift = 10,
>> +		.table = mux_table_sys_ab_clk,
>> +	},
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "sys_a_sel",
>> +		.ops = &clk_regmap_mux_ro_ops,
>> +		.parent_data = sys_ab_clk_parent_data,
>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>> +	},
>> +};
>> +
>> +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,
>> +		.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,
> 
> SET_RATE_PARENT ?
> 
the ops is RO, Maybe no flag is better.
>> +	},
>> +};
>> +
>> +/* 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 };
> 
> useless
> 
ok, I will delete the table.
>> +
>> +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", },
>> +	{ .hw = &a1_fclk_div2.hw },
>> +	{ .hw = &a1_fclk_div3.hw },
>> +	{ .hw = &a1_fclk_div5.hw },
>> +	{ .hw = &a1_hifi_pll.hw },
>> +	{ .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 | CLK_IGNORE_UNUSED,
> 
> This CLK_IGNORE_UNUSED, if justified, needs to be explained
> 
ok, DSP cowork withe ARM in A1, dsp clock shoud not be changed at runtime.
>> +	},
>> +};
>> +
>> +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 | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +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_hws = (const struct clk_hw *[]) {
>> +			&a1_fclk_div2.hw
>> +		},
>> +		.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 */
> 
> Either put something helpful or don't put anything
> For example explaining why there is a hole in the table bellow and what
> is parent 4 (if any) would be helpful.
ok, parent 2 is sys_pll_div16, sys pll and related clock are not 
completeed, parent 4 is one of clock measurement source, it relies on
the clock measurement register configuration.
gen clock is a debug and monitor clock.
> 
>> +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 },
>> +	{ .hw = &a1_hifi_pll.hw },
>> +	{ .hw = &a1_fclk_div2.hw },
>> +	{ .hw = &a1_fclk_div3.hw },
>> +	{ .hw = &a1_fclk_div5.hw },
>> +	{ .hw = &a1_fclk_div7.hw },
>> +};
>> +
>> +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 },
>> +};
>> +
>> +/*
>> + * add CLK_IGNORE_UNUSED flag for pwm controller GATE
>> + * clk core will disable unused clock, it may disable
>> + * vddcore voltage which contrlled by one pwm in bl21.
>                               ^
>                               typo
> 
>> + * add the flag to avoid changing cpu voltage.
> 
> 80 char per line is ok
> This comment would be better placed next to the corresponding flag
> 
> Also you could explain that flag could be removed when CCF has some
> hand-off mechanism (similar comments you can copy in other driver)
> 
ok,  contrlled --> controlled
I will move the comment next to the flag
I have gotten the similar comments in g12a.c
>> + */
>> +/* 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,
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +

[...]

>> +/* usb bus clk */
>> +static const struct clk_parent_data usb_bus_parent_data[] = {
>> +	{ .fw_name = "xtal", },
>> +	{ .hw = &a1_sys_clk.hw },
>> +	{ .hw = &a1_fclk_div3.hw },
>> +	{ .hw = &a1_fclk_div5.hw },
>> +};
>> +
>> +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 | CLK_IGNORE_UNUSED,
> 
> Again, every unused flag need to be properly explained
> 
ok, I will confirm this flag
>> +	},
>> +};
>> +
>> +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 | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +
>> +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 | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +

[...]

>> +
>> +/* dmc clk */
>> +static const struct clk_hw *dmc_parent_hws[] = {
>> +	&a1_fclk_div2.hw,
>> +	&a1_fclk_div3.hw,
>> +	&a1_fclk_div5.hw,
>> +	&a1_hifi_pll.hw,
>> +};
>> +
>> +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_hws = dmc_parent_hws,
>> +		.num_parents = ARRAY_SIZE(dmc_parent_hws),
>> +	},
>> +};
>> +
>> +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,
>> +		/*
>> +		 * add CLK_IGNORE_UNUSED to avoid hangup
>> +		 * DDR clock should not change at runtime
>> +		 */
> 
> CRITICAL ? RO ops maybe ?
RO ops is better
> 
>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>> +	},
>> +};
>> +

[...]

>> +
>> +#define MESON_GATE(_name, _reg, _bit) \
>> +	MESON_PCLK(_name, _reg, _bit, &a1_sys_clk.hw)
>> +
>> +/* CLKTREE_SYS_CLK_EN0 */
> 
> Full caps is not ok ... and once again, try to add comment which helps
ok, I will add some useful comment.
> 
>> +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);
>> +/* CLKTREE_SYS_CLK_EN1 */
>> +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);
>> +/* CLKTREE_AXI_CLK_EN */
>> +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);
>> +

[...]

>> +
>> +/* Convenience table to populate regmap in .probe
>> + * Peripheral clock register base address is 0xfe000800
> 
> this info will be in DT
I will remove the address commit
> 
>> + */

[...]

>> +
>> +/*
>> + * cpu clock register base address is 0xfd000080
>> + */
>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>> +	/* TODO */
>> +};
>> +
>> +/*
>> + * pll clock register base address is 0xfe007c00
>> + */
>> +static struct clk_regmap *const a1_pll_clk_regmaps[] = {
>> +	&a1_fixed_pll_dco,
>> +	&a1_fixed_pll,
>> +	&a1_hifi_pll,
>> +	&a1_fclk_div2,
>> +	&a1_fclk_div3,
>> +	&a1_fclk_div5,
>> +	&a1_fclk_div7,
>> +};
>> +
>> +static struct regmap_config clkc_regmap_config = {
>> +	.reg_bits       = 32,
>> +	.val_bits       = 32,
>> +	.reg_stride     = 4,
>> +};
>> +
>> +static struct regmap *a1_regmap_resource(struct device *dev, char *name)
>> +{
>> +	struct resource res;
>> +	void __iomem *base;
>> +	int i;
>> +	struct device_node *node = dev->of_node;
>> +
>> +	i = of_property_match_string(node, "reg-names", name);
>> +	if (of_address_to_resource(node, i, &res))
>> +		return ERR_PTR(-ENOENT);
>> +
>> +	base = devm_ioremap_resource(dev, &res);
>> +	if (IS_ERR(base))
>> +		return ERR_CAST(base);
>> +
>> +	clkc_regmap_config.max_register = resource_size(&res) - 4;
>> +	clkc_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
>> +						 "%s-%s", node->name,
>> +						 name);
>> +	if (!clkc_regmap_config.name)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	return devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
>> +}
>> +
>> +static int a1_clkc_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct regmap *peripheral_map, *pll_map, *cpu_map;
>> +	int ret, i;
>> +
>> +	/* Get regmap for different clock area */
>> +	peripheral_map = a1_regmap_resource(dev, "peripheral");
>> +	if (IS_ERR(peripheral_map)) {
>> +		dev_err(dev, "peripheral clk registers not found\n");
>> +		return PTR_ERR(peripheral_map);
>> +	}
>> +
>> +	pll_map = a1_regmap_resource(dev, "pll");
>> +	if (IS_ERR(pll_map)) {
>> +		dev_err(dev, "pll clk registers not found\n");
>> +		return PTR_ERR(pll_map);
>> +	}
>> +
>> +	cpu_map = a1_regmap_resource(dev, "cpu");
>> +	if (IS_ERR(cpu_map)) {
>> +		dev_err(dev, "cpu clk registers not found\n");
>> +		return PTR_ERR(cpu_map);
>> +	}
>> +
>> +	/* Populate regmap for the regmap backed clocks */
>> +	for (i = 0; i < ARRAY_SIZE(a1_clk_regmaps); i++)
>> +		a1_clk_regmaps[i]->map = peripheral_map;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(a1_cpu_clk_regmaps); i++)
>> +		a1_cpu_clk_regmaps[i]->map = cpu_map;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(a1_pll_clk_regmaps); i++)
>> +		a1_pll_clk_regmaps[i]->map = pll_map;
> 
> Unless you have a rock solid reason why you absolutely need to make
> single controller out of this 3 regions, Nack.
> 
As comment replying in 
Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml, I will 
implement three clock drivers.
>> +
>> +	for (i = 0; i < a1_hw_onecell_data.num; i++) {
>> +		/* array might be sparse */
>> +		if (!a1_hw_onecell_data.hws[i])
>> +			continue;
>> +
>> +		ret = devm_clk_hw_register(dev, a1_hw_onecell_data.hws[i]);
>> +		if (ret) {
>> +			dev_err(dev, "Clock registration failed\n");
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
>> +					   &a1_hw_onecell_data);
>> +}
>> +
>> +static const struct of_device_id clkc_match_table[] = {
>> +	{ .compatible = "amlogic,a1-clkc" },
>> +	{ /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver a1_driver = {
>> +	.probe		= a1_clkc_probe,
>> +	.driver		= {
>> +		.name	= "a1-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..f2291c4
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1.h
>> @@ -0,0 +1,172 @@
>> +/* 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 address
>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe000800
> 
> Again this info is DT and might become wrong if your controller is ever
> compatible with another SoC
> 
I will remove the address comment, the right address is 0xfe000080.
>> + */
>> +#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
>> +/*
>> + * For PLL register offset
>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe007c00
>> + */
>> +#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
>> +/*
>> + * CPU clok register offset
>> + * APB_BASE:  APB1_BASE_ADDR = 0xfd000080
>> + */
>> +#define CPUCTRL_CLK_CTRL0		0x00
>> +#define CPUCTRL_CLK_CTRL1		0x04
>> +#define CPUCTRL_CLK_CTRL2		0x08
>> +#define CPUCTRL_CLK_CTRL3		0x0c
>> +#define CPUCTRL_CLK_CTRL4		0x10
>> +#define CPUCTRL_CLK_CTRL5		0x14
>> +#define CPUCTRL_CLK_CTRL6		0x18
>> +#define CPUCTRL_CLK_CTRL7		0x1c
>> +
>> +#define CLKID_FIXED_PLL_DCO		0
>> +#define CLKID_SYS_A_SEL			10
>> +#define CLKID_SYS_A_DIV			11
>> +#define CLKID_SYS_A			12
>> +#define CLKID_SYS_B_SEL			13
>> +#define CLKID_SYS_B_DIV			14
>> +#define CLKID_SYS_B			15
>> +#define CLKID_XTAL_CLKTREE		18
>> +#define CLKID_XTAL_FIXPLL		19
>> +#define CLKID_XTAL_USB_PHY		20
>> +#define CLKID_XTAL_USB_CTRL		21
>> +#define CLKID_XTAL_HIFIPLL		22
>> +#define CLKID_XTAL_SYSPLL		23
>> +#define CLKID_XTAL_DDS			24
>> +#define CLKID_DSPA_A_SEL		78
>> +#define CLKID_DSPA_A_DIV		79
>> +#define CLKID_DSPA_A			80
>> +#define CLKID_DSPA_B_SEL		81
>> +#define CLKID_DSPA_B_DIV		82
>> +#define CLKID_DSPA_B			83
>> +#define CLKID_DSPB_A_SEL		85
>> +#define CLKID_DSPB_A_DIV		86
>> +#define CLKID_DSPB_A			87
>> +#define CLKID_DSPB_B_SEL		88
>> +#define CLKID_DSPB_B_DIV		89
>> +#define CLKID_DSPB_B			90
>> +#define CLKID_RTC_32K_CLKIN		96
>> +#define CLKID_RTC_32K_DIV		97
>> +#define CLKID_RTC_32K_XTAL		98
>> +#define CLKID_RTC_32K_SEL		99
>> +#define CLKID_CECB_32K_CLKIN		106
>> +#define CLKID_CECB_32K_DIV		107
>> +#define CLKID_CECB_32K_SEL_PRE		108
>> +#define CLKID_CECB_32K_SEL		109
>> +#define CLKID_CECA_32K_CLKIN		101
>> +#define CLKID_CECA_32K_DIV		102
>> +#define CLKID_CECA_32K_SEL_PRE		103
>> +#define CLKID_CECA_32K_SEL		104
>> +#define CLKID_DIV2_PRE			113
>> +#define CLKID_24M_DIV2			115
>> +#define CLKID_GEN_SEL			116
>> +#define CLKID_GEN_DIV			117
>> +#define CLKID_SARADC_DIV		120
>> +#define CLKID_PWM_A_SEL			122
>> +#define CLKID_PWM_A_DIV			123
>> +#define CLKID_PWM_B_SEL			125
>> +#define CLKID_PWM_B_DIV			126
>> +#define CLKID_PWM_C_SEL			128
>> +#define CLKID_PWM_C_DIV			129
>> +#define CLKID_PWM_D_SEL			131
>> +#define CLKID_PWM_D_DIV			132
>> +#define CLKID_PWM_E_SEL			134
>> +#define CLKID_PWM_E_DIV			135
>> +#define CLKID_PWM_F_SEL			137
>> +#define CLKID_PWM_F_DIV			138
>> +#define CLKID_SPICC_SEL			140
>> +#define CLKID_SPICC_DIV			141
>> +#define CLKID_SPICC_SEL2		142
>> +#define CLKID_TS_DIV			144
>> +#define CLKID_SPIFC_SEL			146
>> +#define CLKID_SPIFC_DIV			147
>> +#define CLKID_SPIFC_SEL2		148
>> +#define CLKID_USB_BUS_SEL		150
>> +#define CLKID_USB_BUS_DIV		151
>> +#define CLKID_SD_EMMC_SEL		153
>> +#define CLKID_SD_EMMC_DIV		154
>> +#define CLKID_SD_EMMC_SEL2		155
>> +#define CLKID_PSRAM_SEL			157
>> +#define CLKID_PSRAM_DIV			158
>> +#define CLKID_PSRAM_SEL2		159
>> +#define CLKID_DMC_SEL			161
>> +#define CLKID_DMC_DIV			162
>> +#define CLKID_DMC_SEL2			163
>> +#define NR_CLKS				165
>> +
>> +#include <dt-bindings/clock/a1-clkc.h>
>> +
>> +#endif /* __A1_H */
>> -- 
>> 1.9.1
> 
> .
> 

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-27  3:11     ` Jian Hu
@ 2019-09-27 12:56       ` Jerome Brunet
  2019-09-29  6:15         ` Jian Hu
  0 siblings, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-09-27 12:56 UTC (permalink / raw)
  To: Jian Hu
  Cc: Stephen Boyd, Jerome Brunet, Neil Armstrong, Rob Herring,
	Jianxin Pan, devicetree, Martin Blumenstingl, Kevin Hilman,
	Michael Turquette, linux-kernel, Qiufang Dai, linux-amlogic,
	linux-clk, linux-arm-kernel


On Fri 27 Sep 2019 at 05:11, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Stephen
>
> Thank you for review
>
> On 2019/9/25 21:12, Stephen Boyd wrote:
>> Quoting Jian Hu (2019-09-25 04:44:48)
>>> The Amlogic A1 clock includes three parts:
>>> 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>
>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>
>> This second name didn't send the patch. Please follow the signoff
>> procedures documented in Documentation/process/submitting-patches.rst
>>
>>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>>> index 16d7614..a48f67d 100644
>>> --- a/arch/arm64/Kconfig.platforms
>>> +++ b/arch/arm64/Kconfig.platforms
>>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>>          select COMMON_CLK_AXG
>>>          select COMMON_CLK_G12A
>>>          select MESON_IRQ_GPIO
>>> +       select COMMON_CLK_A1
>>
>> Sort?
> ok, I will put it behind COMMON_CLK_AXG
>>
>>>          help
>>>            This enables support for the arm64 based Amlogic SoCs
>>>            such as the s905, S905X/D, S912, A113X/D or S905X/D2
>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>> index dabeb43..e6cb4c3 100644
>>> --- a/drivers/clk/meson/Kconfig
>>> +++ b/drivers/clk/meson/Kconfig
>>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>>          help
>>>            Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>>            devices, aka g12a. Say Y if you want peripherals to work.
>>> +
>>> +config COMMON_CLK_A1
>>
>> Probably should be placed somewhere alphabetically in this file?
> ok, I will put it behind COMMON_CLK_AXG_AUDIO
>>
>>> +       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.
>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>> index 3939f21..6be3a8f 100644
>>> --- a/drivers/clk/meson/Makefile
>>> +++ b/drivers/clk/meson/Makefile
>>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
>>
>> I would guess this should be sorted on Kconfig name in this file?
> ok, I will put it behind COMMON_CLK_AXG_AUDIO
>>
>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>> new file mode 100644
>>> index 0000000..26edae0f
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1.c
>>> @@ -0,0 +1,2617 @@
>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + */
>>> +
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/init.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/of_address.h>
>>> +#include "clk-mpll.h"
>>> +#include "clk-pll.h"
>>> +#include "clk-regmap.h"
>>> +#include "vid-pll-div.h"
>>> +#include "clk-dualdiv.h"
>>> +#include "meson-eeclk.h"
>>> +#include "a1.h"
>>> +
>> [...]
>>> +
>>> +/*
>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>> + * a strict register sequence to enable the PLL.
>>> + * set meson_clk_pcie_pll_ops as its ops
>>
>> Please remove this last line as it's obvious from the code what ops are
>> used.
>>
> ok, I will remove it.
>>> + */
>>> +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,
>>> +               },
>>> +               .table = a1_hifi_pll_params_table,
>>> +               .init_regs = a1_hifi_init_regs,
>>> +               .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>> +       },
>>> +       .hw.init = &(struct clk_init_data){
>>> +               .name = "hifi_pll",
>>> +               .ops = &meson_clk_pcie_pll_ops,
>>> +               .parent_hws = (const struct clk_hw *[]) {
>>> +                       &a1_xtal_hifipll.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,
>>> +               /*
>>> +                * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>> +                * or its children clocks.
>>
>> This comment is useless. Please replace it with an actual reason for
>> keeping the clk on instead of describing what the flag does.
>>
> ok, The actual reason is it should not change at runtime.

Yeah, from the flag we understand that you want to keep this on. What we
are after is why ? What device is using this clock and cannot tolerate
this gate to turn off ?

This is important and this is kind of comment we are after.
These flag should be viewed as "mid term work around". In the end, there
should be a driver for your device which claims the clock and properly
manage it

>>> +                */
>>> +               .flags = CLK_IS_CRITICAL,
>>> +       },
>>> +};
>>> +
>> [..]
>>> +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,
>>> +               /*
>>> +                * add CLK_IGNORE_UNUSED to avoid hangup
>>> +                * DDR clock should not change at runtime
>>> +                */
>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>
>> So not CLK_IS_CRITICAL?
> Yes, CLK_IS_CRITICAL is better, I will change it.

Same comment as above.

>>
>>> +       },
>>> +};
>>> +
>> [...]
>>> +
>>> +/*
>>> + * cpu clock register base address is 0xfd000080
>>> + */
>>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>>> +       /* TODO */
>>
>> Can it be done?
> I plan to compelte cpu clock with the DVFS verified. And  Some peripheral
> devices rely on this patch to send. I prefer to do it in the next patch.
>>
>>> +};
>>
>> .
>>


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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-27  9:52     ` Jian Hu
@ 2019-09-27 13:32       ` Jerome Brunet
  2019-09-29  9:38         ` Jian Hu
  0 siblings, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-09-27 13:32 UTC (permalink / raw)
  To: Jian Hu
  Cc: Jerome Brunet, Neil Armstrong, Jianxin Pan, Kevin Hilman,
	Rob Herring, Martin Blumenstingl, Michael Turquette,
	Stephen Boyd, Qiufang Dai, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree


On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Jerome
>
> Thank you for review.
>
> On 2019/9/25 23:09, Jerome Brunet wrote:
>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> The Amlogic A1 clock includes three parts:
>>> 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>
>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>> ---
>>>   arch/arm64/Kconfig.platforms |    1 +
>>>   drivers/clk/meson/Kconfig    |   10 +
>>>   drivers/clk/meson/Makefile   |    1 +
>>>   drivers/clk/meson/a1.c       | 2617 ++++++++++++++++++++++++++++++++++++++++++
>>>   drivers/clk/meson/a1.h       |  172 +++
>>>   5 files changed, 2801 insertions(+)
>>>   create mode 100644 drivers/clk/meson/a1.c
>>>   create mode 100644 drivers/clk/meson/a1.h
>>>
>>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>>> index 16d7614..a48f67d 100644
>>> --- a/arch/arm64/Kconfig.platforms
>>> +++ b/arch/arm64/Kconfig.platforms
>>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>>   	select COMMON_CLK_AXG
>>>   	select COMMON_CLK_G12A
>>>   	select MESON_IRQ_GPIO
>>> +	select COMMON_CLK_A1
>>
>> This need to be separate patch addressed to Kevin once your driver is merged
>>
> ok, I will remove it in PATCH V2. And send it again after the driver is
> merged.
>>>   	help
>>>   	  This enables support for the arm64 based Amlogic SoCs
>>>   	  such as the s905, S905X/D, S912, A113X/D or S905X/D2
>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>> index dabeb43..e6cb4c3 100644
>>> --- a/drivers/clk/meson/Kconfig
>>> +++ b/drivers/clk/meson/Kconfig
>>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>>   	help
>>>   	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>>   	  devices, aka g12a. Say Y if you want peripherals 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.
>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>> index 3939f21..6be3a8f 100644
>>> --- a/drivers/clk/meson/Makefile
>>> +++ b/drivers/clk/meson/Makefile
>>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>> new file mode 100644
>>> index 0000000..26edae0f
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1.c
>>> @@ -0,0 +1,2617 @@
>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>> +/*
>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>> + */
>>> +
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/init.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/of_address.h>
>>> +#include "clk-mpll.h"
>>> +#include "clk-pll.h"
>>> +#include "clk-regmap.h"
>>> +#include "vid-pll-div.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_ops,
>>> +		.parent_data = &(const struct clk_parent_data) {
>>> +			.fw_name = "xtal",
>>> +		},
>>> +		.num_parents = 1,
>>> +		.flags = CLK_IS_CRITICAL,
>>
>> Is CCF even expected to touch this ever ? what about RO ops ?
>> Please review your other clocks with this in mind
>>
> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +		.flags = CLK_IS_CRITICAL,
>>
>> How is an USB clock critical to the system ?
>> Please review your other clocks with comment in mind ...
> the usb clock does not affect the system,
> remove the CLK_IS_CRITICAL flag
>>
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
> the usb clock does not affect the system,
> remove the CLK_IS_CRITICAL flag
>>> +
>>> +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,
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
> CLK_IS_CRITICAL is need to lock hifi pll.

That's not how CCF works, this falg is not ok here.
CCF will enable this clock before calling enable on your hifi pll

>>> +
>>> +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,
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>> +
> when CPU clock is at fixed clock, sys pll
> will be disabled, xtal_syspll will be disabled too.
> when setting sys pll, call clk_set_rate to lock
> sys pll, add RO ops to avoid disabling the clock

Again not Ok.
If you mechanism to lock the PLL is properly implemented in the enable
callback of the sys pll, still kind of work around are not needed

This has worked on the pll we had so far.

>
>>> +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,
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
> CLK_IS_CRITICAL is need to lock dds
>>> +
>>> +/* fixed pll = 1536M
>>> + *
>>> + * fixed pll ----- fclk_div2 = 768M
>>> + *           |
>>> + *           ----- fclk_div3 = 512M
>>> + *           |
>>> + *           ----- fclk_div5 = 307.2M
>>> + *           |
>>> + *           ----- fclk_div7 = 219.4M
>>> + */
>>
>> The framework will make those calculation ... you can remove this
>>
> ok, I will remote the comment.
>>> +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_hws = (const struct clk_hw *[]) {
>>> +			&a1_xtal_fixpll.hw
>>> +		},
>>> +		.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,
>>> +		.flags = CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>> +	PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>> +};
>>> +
>>> +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 = 0x10022200 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x00301000 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 10 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0,	.def = 0x15f11480, .delay_us = 40 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001140 },
>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001100 },
>>> +};
>>> +
>>> +/*
>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>> + * a strict register sequence to enable the PLL.
>>> + * set meson_clk_pcie_pll_ops as its ops
>>> + */
>>
>> Could you elaborate on this ? What need to be done to enable the clock ?
>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>> might be desirable for audio use case. Why is this one restricted to one
>> particular rate ?
>>
> The audio working frequency are 44.1khz, 48khz and 192khz.
>
> 614.4M can meet the three frequency.
>
> after the hifi pll, there are two dividers in Audio clock.
>
> 614.4M/3200 = 192khz
>
> 614.4M/12800 = 48khz
>
> 614,4M/13932 = 44.0999khz

It does not really answer my question though.
You are locking a use case here, which is 32 bit sample width

We have other constraint with the upstream audio driver, and we usually
looking for base frequency that a multiple of 768 (24*32).

If you need your PLL to be set to a particular rate for a use case, the
correct way is "assigned-rate" in DT

so the question still stands, the HIFI pll before was pretty easy to set
at a wide variety of rate (same as GP0) ... is it not the case anymore ?
If yes, could you decribe the constraints.

All this took us a long time to figure out on our own, which is why I'd
prefer to get the proper constraints in from the beginning this time


>
>>> +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,
>>> +		},
>>> +		.table = a1_hifi_pll_params_table,
>>> +		.init_regs = a1_hifi_init_regs,
>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "hifi_pll",
>>> +		.ops = &meson_clk_pcie_pll_ops,
>>> +		.parent_hws = (const struct clk_hw *[]) {
>>> +			&a1_xtal_hifipll.hw
>>> +		},
>>> +		.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,
>>> +		/*
>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>> +		 * or its children clocks.
>>> +		 */
>>
>> The meaning of this flag is already documented in clk-provider.h
>> The reason why you need this flag is lot more interesting here ...
>>
>> Same below
> ok, I will replace new comments here.
>>
>>> +		.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,
>>> +		/*
>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>> +		 * its children clocks.
>>> +		 */
>>> +		.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,
>>> +		/*
>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>> +		 * its children clocks.
>>> +		 */
>>> +		.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 = 23,
>>> +	},
>>> +	.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,
>>> +		/*
>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>> +		 * or its children clock.
>>> +		 */
>>> +		.flags = CLK_IS_CRITICAL,
>>> +	},
>>> +};
>>> +
>>> +/* sys clk = 64M */
>>
>> Again this comment does not help understanding the driver code, please
>> remove
>>
> got it.
>>> +static u32 mux_table_sys_ab_clk[] = { 0, 1, 2, 3};
>>
>> This table is useless
>>
>>> +static const struct clk_parent_data sys_ab_clk_parent_data[] = {
>>> +	{ .fw_name = "xtal", },
>>> +	{ .hw = &a1_fclk_div2.hw },
>>> +	{ .hw = &a1_fclk_div3.hw },
>>> +	{ .hw = &a1_fclk_div5.hw },
>>> +};
>>> +
>>> +static struct clk_regmap a1_sys_b_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = SYS_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 26,
>>> +		.table = mux_table_sys_ab_clk,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "sys_b_sel",
>>> +		.ops = &clk_regmap_mux_ro_ops,
>>> +		.parent_data = sys_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>
>> Why does this need to be critical ?
>> The a1_sys_clk (leaf of the block) could possibly be critical (if you
>> explain why) ... but the flag should not be needed in the middle of the
>> block
>>
> ok, the a1_sys_clk should not be changed at runtime, it is the same with
> the clk81 clock in G12A. Just use another name in A1.

This does not justify the clock to be critical.

#1 Why can't it be changed ?
#2 CLK_IS_CRITICAL does not say that clock can't change, it says it
   can't gate ... two different things


>>> +	},
>>> +};
>>> +
>>> +static struct clk_regmap a1_sys_a_sel = {
>>> +	.data = &(struct clk_regmap_mux_data){
>>> +		.offset = SYS_CLK_CTRL0,
>>> +		.mask = 0x7,
>>> +		.shift = 10,
>>> +		.table = mux_table_sys_ab_clk,
>>> +	},
>>> +	.hw.init = &(struct clk_init_data){
>>> +		.name = "sys_a_sel",
>>> +		.ops = &clk_regmap_mux_ro_ops,
>>> +		.parent_data = sys_ab_clk_parent_data,
>>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +		.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,
>>
>> SET_RATE_PARENT ?
>>
> the ops is RO, Maybe no flag is better.

Is RO for now but setting the rate propagation properly fromt the
beginning is preferred.

In general, you should have SET_RATE_PARENT everywhere unless there is a
reason to stop the rate propagation.

>>> +	},
>>> +};
>>> +
>>> +/* 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 };
>>
>> useless
>>
> ok, I will delete the table.
>>> +
>>> +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", },
>>> +	{ .hw = &a1_fclk_div2.hw },
>>> +	{ .hw = &a1_fclk_div3.hw },
>>> +	{ .hw = &a1_fclk_div5.hw },
>>> +	{ .hw = &a1_hifi_pll.hw },
>>> +	{ .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 | CLK_IGNORE_UNUSED,
>>
>> This CLK_IGNORE_UNUSED, if justified, needs to be explained
>>
> ok, DSP cowork withe ARM in A1, dsp clock shoud not be changed at
> runtime.

#1: UNUSED only guarantee that the clock won't be gated in the late init
 if. No guarantee whatsoever after that.
#2: If you have a DSP that need a clock active at particular rate, write
 a driver for it and use the clock API. Don't throw your use case
 constraints in the tree def.

Please review all occurrences of CRITICAL, RO, IGNORE_UNUSED before
sending a v2.

>>> +	},
>>> +};
>>> +
>>> +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 | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +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_hws = (const struct clk_hw *[]) {
>>> +			&a1_fclk_div2.hw
>>> +		},
>>> +		.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 */
>>
>> Either put something helpful or don't put anything
>> For example explaining why there is a hole in the table bellow and what
>> is parent 4 (if any) would be helpful.
> ok, parent 2 is sys_pll_div16, sys pll and related clock are not
> completeed, parent 4 is one of clock measurement source, it relies on
> the clock measurement register configuration.
> gen clock is a debug and monitor clock.
>>
>>> +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 },
>>> +	{ .hw = &a1_hifi_pll.hw },
>>> +	{ .hw = &a1_fclk_div2.hw },
>>> +	{ .hw = &a1_fclk_div3.hw },
>>> +	{ .hw = &a1_fclk_div5.hw },
>>> +	{ .hw = &a1_fclk_div7.hw },
>>> +};
>>> +
>>> +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 },
>>> +};
>>> +
>>> +/*
>>> + * add CLK_IGNORE_UNUSED flag for pwm controller GATE
>>> + * clk core will disable unused clock, it may disable
>>> + * vddcore voltage which contrlled by one pwm in bl21.
>>                               ^
>>                               typo
>>
>>> + * add the flag to avoid changing cpu voltage.
>>
>> 80 char per line is ok
>> This comment would be better placed next to the corresponding flag
>>
>> Also you could explain that flag could be removed when CCF has some
>> hand-off mechanism (similar comments you can copy in other driver)
>>
> ok,  contrlled --> controlled
> I will move the comment next to the flag
> I have gotten the similar comments in g12a.c
>>> + */
>>> +/* 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,
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>
> [...]
>
>>> +/* usb bus clk */
>>> +static const struct clk_parent_data usb_bus_parent_data[] = {
>>> +	{ .fw_name = "xtal", },
>>> +	{ .hw = &a1_sys_clk.hw },
>>> +	{ .hw = &a1_fclk_div3.hw },
>>> +	{ .hw = &a1_fclk_div5.hw },
>>> +};
>>> +
>>> +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 | CLK_IGNORE_UNUSED,
>>
>> Again, every unused flag need to be properly explained
>>
> ok, I will confirm this flag
>>> +	},
>>> +};
>>> +
>>> +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 | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>>> +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 | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>
> [...]
>
>>> +
>>> +/* dmc clk */
>>> +static const struct clk_hw *dmc_parent_hws[] = {
>>> +	&a1_fclk_div2.hw,
>>> +	&a1_fclk_div3.hw,
>>> +	&a1_fclk_div5.hw,
>>> +	&a1_hifi_pll.hw,
>>> +};
>>> +
>>> +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_hws = dmc_parent_hws,
>>> +		.num_parents = ARRAY_SIZE(dmc_parent_hws),
>>> +	},
>>> +};
>>> +
>>> +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,
>>> +		/*
>>> +		 * add CLK_IGNORE_UNUSED to avoid hangup
>>> +		 * DDR clock should not change at runtime
>>> +		 */
>>
>> CRITICAL ? RO ops maybe ?
> RO ops is better
>>
>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>> +	},
>>> +};
>>> +
>
> [...]
>
>>> +
>>> +#define MESON_GATE(_name, _reg, _bit) \
>>> +	MESON_PCLK(_name, _reg, _bit, &a1_sys_clk.hw)
>>> +
>>> +/* CLKTREE_SYS_CLK_EN0 */
>>
>> Full caps is not ok ... and once again, try to add comment which helps
> ok, I will add some useful comment.
>>
>>> +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);
>>> +/* CLKTREE_SYS_CLK_EN1 */
>>> +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);
>>> +/* CLKTREE_AXI_CLK_EN */
>>> +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);
>>> +
>
> [...]
>
>>> +
>>> +/* Convenience table to populate regmap in .probe
>>> + * Peripheral clock register base address is 0xfe000800
>>
>> this info will be in DT
> I will remove the address commit
>>
>>> + */
>
> [...]
>
>>> +
>>> +/*
>>> + * cpu clock register base address is 0xfd000080
>>> + */
>>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>>> +	/* TODO */
>>> +};
>>> +
>>> +/*
>>> + * pll clock register base address is 0xfe007c00
>>> + */
>>> +static struct clk_regmap *const a1_pll_clk_regmaps[] = {
>>> +	&a1_fixed_pll_dco,
>>> +	&a1_fixed_pll,
>>> +	&a1_hifi_pll,
>>> +	&a1_fclk_div2,
>>> +	&a1_fclk_div3,
>>> +	&a1_fclk_div5,
>>> +	&a1_fclk_div7,
>>> +};
>>> +
>>> +static struct regmap_config clkc_regmap_config = {
>>> +	.reg_bits       = 32,
>>> +	.val_bits       = 32,
>>> +	.reg_stride     = 4,
>>> +};
>>> +
>>> +static struct regmap *a1_regmap_resource(struct device *dev, char *name)
>>> +{
>>> +	struct resource res;
>>> +	void __iomem *base;
>>> +	int i;
>>> +	struct device_node *node = dev->of_node;
>>> +
>>> +	i = of_property_match_string(node, "reg-names", name);
>>> +	if (of_address_to_resource(node, i, &res))
>>> +		return ERR_PTR(-ENOENT);
>>> +
>>> +	base = devm_ioremap_resource(dev, &res);
>>> +	if (IS_ERR(base))
>>> +		return ERR_CAST(base);
>>> +
>>> +	clkc_regmap_config.max_register = resource_size(&res) - 4;
>>> +	clkc_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
>>> +						 "%s-%s", node->name,
>>> +						 name);
>>> +	if (!clkc_regmap_config.name)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	return devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
>>> +}
>>> +
>>> +static int a1_clkc_probe(struct platform_device *pdev)
>>> +{
>>> +	struct device *dev = &pdev->dev;
>>> +	struct regmap *peripheral_map, *pll_map, *cpu_map;
>>> +	int ret, i;
>>> +
>>> +	/* Get regmap for different clock area */
>>> +	peripheral_map = a1_regmap_resource(dev, "peripheral");
>>> +	if (IS_ERR(peripheral_map)) {
>>> +		dev_err(dev, "peripheral clk registers not found\n");
>>> +		return PTR_ERR(peripheral_map);
>>> +	}
>>> +
>>> +	pll_map = a1_regmap_resource(dev, "pll");
>>> +	if (IS_ERR(pll_map)) {
>>> +		dev_err(dev, "pll clk registers not found\n");
>>> +		return PTR_ERR(pll_map);
>>> +	}
>>> +
>>> +	cpu_map = a1_regmap_resource(dev, "cpu");
>>> +	if (IS_ERR(cpu_map)) {
>>> +		dev_err(dev, "cpu clk registers not found\n");
>>> +		return PTR_ERR(cpu_map);
>>> +	}
>>> +
>>> +	/* Populate regmap for the regmap backed clocks */
>>> +	for (i = 0; i < ARRAY_SIZE(a1_clk_regmaps); i++)
>>> +		a1_clk_regmaps[i]->map = peripheral_map;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(a1_cpu_clk_regmaps); i++)
>>> +		a1_cpu_clk_regmaps[i]->map = cpu_map;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(a1_pll_clk_regmaps); i++)
>>> +		a1_pll_clk_regmaps[i]->map = pll_map;
>>
>> Unless you have a rock solid reason why you absolutely need to make
>> single controller out of this 3 regions, Nack.
>>
> As comment replying in
> Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml, I will
> implement three clock drivers.
>>> +
>>> +	for (i = 0; i < a1_hw_onecell_data.num; i++) {
>>> +		/* array might be sparse */
>>> +		if (!a1_hw_onecell_data.hws[i])
>>> +			continue;
>>> +
>>> +		ret = devm_clk_hw_register(dev, a1_hw_onecell_data.hws[i]);
>>> +		if (ret) {
>>> +			dev_err(dev, "Clock registration failed\n");
>>> +			return ret;
>>> +		}
>>> +	}
>>> +
>>> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
>>> +					   &a1_hw_onecell_data);
>>> +}
>>> +
>>> +static const struct of_device_id clkc_match_table[] = {
>>> +	{ .compatible = "amlogic,a1-clkc" },
>>> +	{ /* sentinel */ }
>>> +};
>>> +
>>> +static struct platform_driver a1_driver = {
>>> +	.probe		= a1_clkc_probe,
>>> +	.driver		= {
>>> +		.name	= "a1-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..f2291c4
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a1.h
>>> @@ -0,0 +1,172 @@
>>> +/* 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 address
>>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe000800
>>
>> Again this info is DT and might become wrong if your controller is ever
>> compatible with another SoC
>>
> I will remove the address comment, the right address is 0xfe000080.
>>> + */
>>> +#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
>>> +/*
>>> + * For PLL register offset
>>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe007c00
>>> + */
>>> +#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
>>> +/*
>>> + * CPU clok register offset
>>> + * APB_BASE:  APB1_BASE_ADDR = 0xfd000080
>>> + */
>>> +#define CPUCTRL_CLK_CTRL0		0x00
>>> +#define CPUCTRL_CLK_CTRL1		0x04
>>> +#define CPUCTRL_CLK_CTRL2		0x08
>>> +#define CPUCTRL_CLK_CTRL3		0x0c
>>> +#define CPUCTRL_CLK_CTRL4		0x10
>>> +#define CPUCTRL_CLK_CTRL5		0x14
>>> +#define CPUCTRL_CLK_CTRL6		0x18
>>> +#define CPUCTRL_CLK_CTRL7		0x1c
>>> +
>>> +#define CLKID_FIXED_PLL_DCO		0
>>> +#define CLKID_SYS_A_SEL			10
>>> +#define CLKID_SYS_A_DIV			11
>>> +#define CLKID_SYS_A			12
>>> +#define CLKID_SYS_B_SEL			13
>>> +#define CLKID_SYS_B_DIV			14
>>> +#define CLKID_SYS_B			15
>>> +#define CLKID_XTAL_CLKTREE		18
>>> +#define CLKID_XTAL_FIXPLL		19
>>> +#define CLKID_XTAL_USB_PHY		20
>>> +#define CLKID_XTAL_USB_CTRL		21
>>> +#define CLKID_XTAL_HIFIPLL		22
>>> +#define CLKID_XTAL_SYSPLL		23
>>> +#define CLKID_XTAL_DDS			24
>>> +#define CLKID_DSPA_A_SEL		78
>>> +#define CLKID_DSPA_A_DIV		79
>>> +#define CLKID_DSPA_A			80
>>> +#define CLKID_DSPA_B_SEL		81
>>> +#define CLKID_DSPA_B_DIV		82
>>> +#define CLKID_DSPA_B			83
>>> +#define CLKID_DSPB_A_SEL		85
>>> +#define CLKID_DSPB_A_DIV		86
>>> +#define CLKID_DSPB_A			87
>>> +#define CLKID_DSPB_B_SEL		88
>>> +#define CLKID_DSPB_B_DIV		89
>>> +#define CLKID_DSPB_B			90
>>> +#define CLKID_RTC_32K_CLKIN		96
>>> +#define CLKID_RTC_32K_DIV		97
>>> +#define CLKID_RTC_32K_XTAL		98
>>> +#define CLKID_RTC_32K_SEL		99
>>> +#define CLKID_CECB_32K_CLKIN		106
>>> +#define CLKID_CECB_32K_DIV		107
>>> +#define CLKID_CECB_32K_SEL_PRE		108
>>> +#define CLKID_CECB_32K_SEL		109
>>> +#define CLKID_CECA_32K_CLKIN		101
>>> +#define CLKID_CECA_32K_DIV		102
>>> +#define CLKID_CECA_32K_SEL_PRE		103
>>> +#define CLKID_CECA_32K_SEL		104
>>> +#define CLKID_DIV2_PRE			113
>>> +#define CLKID_24M_DIV2			115
>>> +#define CLKID_GEN_SEL			116
>>> +#define CLKID_GEN_DIV			117
>>> +#define CLKID_SARADC_DIV		120
>>> +#define CLKID_PWM_A_SEL			122
>>> +#define CLKID_PWM_A_DIV			123
>>> +#define CLKID_PWM_B_SEL			125
>>> +#define CLKID_PWM_B_DIV			126
>>> +#define CLKID_PWM_C_SEL			128
>>> +#define CLKID_PWM_C_DIV			129
>>> +#define CLKID_PWM_D_SEL			131
>>> +#define CLKID_PWM_D_DIV			132
>>> +#define CLKID_PWM_E_SEL			134
>>> +#define CLKID_PWM_E_DIV			135
>>> +#define CLKID_PWM_F_SEL			137
>>> +#define CLKID_PWM_F_DIV			138
>>> +#define CLKID_SPICC_SEL			140
>>> +#define CLKID_SPICC_DIV			141
>>> +#define CLKID_SPICC_SEL2		142
>>> +#define CLKID_TS_DIV			144
>>> +#define CLKID_SPIFC_SEL			146
>>> +#define CLKID_SPIFC_DIV			147
>>> +#define CLKID_SPIFC_SEL2		148
>>> +#define CLKID_USB_BUS_SEL		150
>>> +#define CLKID_USB_BUS_DIV		151
>>> +#define CLKID_SD_EMMC_SEL		153
>>> +#define CLKID_SD_EMMC_DIV		154
>>> +#define CLKID_SD_EMMC_SEL2		155
>>> +#define CLKID_PSRAM_SEL			157
>>> +#define CLKID_PSRAM_DIV			158
>>> +#define CLKID_PSRAM_SEL2		159
>>> +#define CLKID_DMC_SEL			161
>>> +#define CLKID_DMC_DIV			162
>>> +#define CLKID_DMC_SEL2			163
>>> +#define NR_CLKS				165
>>> +
>>> +#include <dt-bindings/clock/a1-clkc.h>
>>> +
>>> +#endif /* __A1_H */
>>> -- 
>>> 1.9.1
>>
>> .
>>


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

* Re: [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-09-25 11:44 ` [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
  2019-09-25 14:29   ` Jerome Brunet
@ 2019-09-27 20:10   ` Rob Herring
  2019-12-18  7:30     ` Jian Hu
  1 sibling, 1 reply; 20+ messages in thread
From: Rob Herring @ 2019-09-27 20:10 UTC (permalink / raw)
  To: Jian Hu
  Cc: Jerome Brunet, Neil Armstrong, Jianxin Pan, devicetree,
	Martin Blumenstingl, Kevin Hilman, Michael Turquette,
	linux-kernel, Stephen Boyd, Qiufang Dai, linux-amlogic,
	linux-clk,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Wed, Sep 25, 2019 at 6:45 AM 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>
> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
> ---
>  .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  65 +++++++++++++
>  include/dt-bindings/clock/a1-clkc.h                | 102 +++++++++++++++++++++
>  2 files changed, 167 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/a1-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..f012eb2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> @@ -0,0 +1,65 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */

(GPL-2.0-only OR BSD-2-Clause) please.

Rob

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-27 12:56       ` Jerome Brunet
@ 2019-09-29  6:15         ` Jian Hu
  0 siblings, 0 replies; 20+ messages in thread
From: Jian Hu @ 2019-09-29  6:15 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Stephen Boyd, Neil Armstrong, Rob Herring, Jianxin Pan,
	devicetree, Martin Blumenstingl, Kevin Hilman, Michael Turquette,
	linux-kernel, Qiufang Dai, linux-amlogic, linux-clk,
	linux-arm-kernel


On 2019/9/27 20:56, Jerome Brunet wrote:
> 
> On Fri 27 Sep 2019 at 05:11, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Stephen
>>
>> Thank you for review
>>
>> On 2019/9/25 21:12, Stephen Boyd wrote:
>>> Quoting Jian Hu (2019-09-25 04:44:48)
>>>> The Amlogic A1 clock includes three parts:
>>>> 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>
>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>
>>> This second name didn't send the patch. Please follow the signoff
>>> procedures documented in Documentation/process/submitting-patches.rst
>>>
>>>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>>>> index 16d7614..a48f67d 100644
>>>> --- a/arch/arm64/Kconfig.platforms
>>>> +++ b/arch/arm64/Kconfig.platforms
>>>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>>>           select COMMON_CLK_AXG
>>>>           select COMMON_CLK_G12A
>>>>           select MESON_IRQ_GPIO
>>>> +       select COMMON_CLK_A1
>>>
>>> Sort?
>> ok, I will put it behind COMMON_CLK_AXG
>>>
>>>>           help
>>>>             This enables support for the arm64 based Amlogic SoCs
>>>>             such as the s905, S905X/D, S912, A113X/D or S905X/D2
>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>> index dabeb43..e6cb4c3 100644
>>>> --- a/drivers/clk/meson/Kconfig
>>>> +++ b/drivers/clk/meson/Kconfig
>>>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>>>           help
>>>>             Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>>>             devices, aka g12a. Say Y if you want peripherals to work.
>>>> +
>>>> +config COMMON_CLK_A1
>>>
>>> Probably should be placed somewhere alphabetically in this file?
>> ok, I will put it behind COMMON_CLK_AXG_AUDIO
>>>
>>>> +       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.
>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>> index 3939f21..6be3a8f 100644
>>>> --- a/drivers/clk/meson/Makefile
>>>> +++ b/drivers/clk/meson/Makefile
>>>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
>>>
>>> I would guess this should be sorted on Kconfig name in this file?
>> ok, I will put it behind COMMON_CLK_AXG_AUDIO
>>>
>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>> new file mode 100644
>>>> index 0000000..26edae0f
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1.c
>>>> @@ -0,0 +1,2617 @@
>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#include <linux/clk-provider.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/of_address.h>
>>>> +#include "clk-mpll.h"
>>>> +#include "clk-pll.h"
>>>> +#include "clk-regmap.h"
>>>> +#include "vid-pll-div.h"
>>>> +#include "clk-dualdiv.h"
>>>> +#include "meson-eeclk.h"
>>>> +#include "a1.h"
>>>> +
>>> [...]
>>>> +
>>>> +/*
>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>> + * a strict register sequence to enable the PLL.
>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>
>>> Please remove this last line as it's obvious from the code what ops are
>>> used.
>>>
>> ok, I will remove it.
>>>> + */
>>>> +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,
>>>> +               },
>>>> +               .table = a1_hifi_pll_params_table,
>>>> +               .init_regs = a1_hifi_init_regs,
>>>> +               .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>> +       },
>>>> +       .hw.init = &(struct clk_init_data){
>>>> +               .name = "hifi_pll",
>>>> +               .ops = &meson_clk_pcie_pll_ops,
>>>> +               .parent_hws = (const struct clk_hw *[]) {
>>>> +                       &a1_xtal_hifipll.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,
>>>> +               /*
>>>> +                * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>>> +                * or its children clocks.
>>>
>>> This comment is useless. Please replace it with an actual reason for
>>> keeping the clk on instead of describing what the flag does.
>>>
>> ok, The actual reason is it should not change at runtime.
> 
> Yeah, from the flag we understand that you want to keep this on. What we
> are after is why ? What device is using this clock and cannot tolerate
> this gate to turn off ?
> 
> This is important and this is kind of comment we are after.
> These flag should be viewed as "mid term work around". In the end, there
> should be a driver for your device which claims the clock and properly
> manage it
> 
I have confirmed for a1_fclk_div2, ddr clock's parent is fclk_div2 which
is initialized in the firmware. The DDR clock could not be gated. I will 
check the other fclk_divX clocks.
>>>> +                */
>>>> +               .flags = CLK_IS_CRITICAL,
>>>> +       },
>>>> +};
>>>> +
>>> [..]
>>>> +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,
>>>> +               /*
>>>> +                * add CLK_IGNORE_UNUSED to avoid hangup
>>>> +                * DDR clock should not change at runtime
>>>> +                */
>>>> +               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>
>>> So not CLK_IS_CRITICAL?
>> Yes, CLK_IS_CRITICAL is better, I will change it.
> 
> Same comment as above.
> 
>>>
>>>> +       },
>>>> +};
>>>> +
>>> [...]
>>>> +
>>>> +/*
>>>> + * cpu clock register base address is 0xfd000080
>>>> + */
>>>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>>>> +       /* TODO */
>>>
>>> Can it be done?
>> I plan to compelte cpu clock with the DVFS verified. And  Some peripheral
>> devices rely on this patch to send. I prefer to do it in the next patch.
>>>
>>>> +};
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-27 13:32       ` Jerome Brunet
@ 2019-09-29  9:38         ` Jian Hu
  2019-10-08  8:03           ` Jian Hu
  0 siblings, 1 reply; 20+ messages in thread
From: Jian Hu @ 2019-09-29  9:38 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, linux-clk, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree



On 2019/9/27 21:32, Jerome Brunet wrote:
> 
> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Jerome
>>
>> Thank you for review.
>>
>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> The Amlogic A1 clock includes three parts:
>>>> 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>
>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>> ---
>>>>    arch/arm64/Kconfig.platforms |    1 +
>>>>    drivers/clk/meson/Kconfig    |   10 +
>>>>    drivers/clk/meson/Makefile   |    1 +
>>>>    drivers/clk/meson/a1.c       | 2617 ++++++++++++++++++++++++++++++++++++++++++
>>>>    drivers/clk/meson/a1.h       |  172 +++
>>>>    5 files changed, 2801 insertions(+)
>>>>    create mode 100644 drivers/clk/meson/a1.c
>>>>    create mode 100644 drivers/clk/meson/a1.h
>>>>
>>>> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
>>>> index 16d7614..a48f67d 100644
>>>> --- a/arch/arm64/Kconfig.platforms
>>>> +++ b/arch/arm64/Kconfig.platforms
>>>> @@ -138,6 +138,7 @@ config ARCH_MESON
>>>>    	select COMMON_CLK_AXG
>>>>    	select COMMON_CLK_G12A
>>>>    	select MESON_IRQ_GPIO
>>>> +	select COMMON_CLK_A1
>>>
>>> This need to be separate patch addressed to Kevin once your driver is merged
>>>
>> ok, I will remove it in PATCH V2. And send it again after the driver is
>> merged.
>>>>    	help
>>>>    	  This enables support for the arm64 based Amlogic SoCs
>>>>    	  such as the s905, S905X/D, S912, A113X/D or S905X/D2
>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>> index dabeb43..e6cb4c3 100644
>>>> --- a/drivers/clk/meson/Kconfig
>>>> +++ b/drivers/clk/meson/Kconfig
>>>> @@ -107,3 +107,13 @@ config COMMON_CLK_G12A
>>>>    	help
>>>>    	  Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
>>>>    	  devices, aka g12a. Say Y if you want peripherals 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.
>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>> index 3939f21..6be3a8f 100644
>>>> --- a/drivers/clk/meson/Makefile
>>>> +++ b/drivers/clk/meson/Makefile
>>>> @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.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
>>>> +obj-$(CONFIG_COMMON_CLK_A1) += a1.o
>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>> new file mode 100644
>>>> index 0000000..26edae0f
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1.c
>>>> @@ -0,0 +1,2617 @@
>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>> +/*
>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>> + */
>>>> +
>>>> +#include <linux/clk-provider.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/of_address.h>
>>>> +#include "clk-mpll.h"
>>>> +#include "clk-pll.h"
>>>> +#include "clk-regmap.h"
>>>> +#include "vid-pll-div.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_ops,
>>>> +		.parent_data = &(const struct clk_parent_data) {
>>>> +			.fw_name = "xtal",
>>>> +		},
>>>> +		.num_parents = 1,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>
>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>> Please review your other clocks with this in mind
>>>
>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>
>>> How is an USB clock critical to the system ?
>>> Please review your other clocks with comment in mind ...
>> the usb clock does not affect the system,
>> remove the CLK_IS_CRITICAL flag
>>>
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>> the usb clock does not affect the system,
>> remove the CLK_IS_CRITICAL flag
>>>> +
>>>> +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,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>> CLK_IS_CRITICAL is need to lock hifi pll.
> 
> That's not how CCF works, this falg is not ok here.
> CCF will enable this clock before calling enable on your hifi pll
> 
ok, I will remove it.
>>>> +
>>>> +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,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>> +
>> when CPU clock is at fixed clock, sys pll
>> will be disabled, xtal_syspll will be disabled too.
>> when setting sys pll, call clk_set_rate to lock
>> sys pll, add RO ops to avoid disabling the clock
> 
> Again not Ok.
> If you mechanism to lock the PLL is properly implemented in the enable
> callback of the sys pll, still kind of work around are not needed
> 
> This has worked on the pll we had so far.
> 
ok, I will remove it.
>>
>>>> +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,
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>> CLK_IS_CRITICAL is need to lock dds
>>>> +
>>>> +/* fixed pll = 1536M
>>>> + *
>>>> + * fixed pll ----- fclk_div2 = 768M
>>>> + *           |
>>>> + *           ----- fclk_div3 = 512M
>>>> + *           |
>>>> + *           ----- fclk_div5 = 307.2M
>>>> + *           |
>>>> + *           ----- fclk_div7 = 219.4M
>>>> + */
>>>
>>> The framework will make those calculation ... you can remove this
>>>
>> ok, I will remote the comment.
>>>> +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_hws = (const struct clk_hw *[]) {
>>>> +			&a1_xtal_fixpll.hw
>>>> +		},
>>>> +		.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,
>>>> +		.flags = CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>> +	PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>> +};
>>>> +
>>>> +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 = 0x10022200 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL4,	.def = 0x00301000 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 10 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL0,	.def = 0x15f11480, .delay_us = 40 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001140 },
>>>> +	{ .reg = ANACTRL_HIFIPLL_CTRL2,	.def = 0x00001100 },
>>>> +};
>>>> +
>>>> +/*
>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>> + * a strict register sequence to enable the PLL.
>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>> + */
>>>
>>> Could you elaborate on this ? What need to be done to enable the clock ?
>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>> might be desirable for audio use case. Why is this one restricted to one
>>> particular rate ?
>>>
>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>
>> 614.4M can meet the three frequency.
>>
>> after the hifi pll, there are two dividers in Audio clock.
>>
>> 614.4M/3200 = 192khz
>>
>> 614.4M/12800 = 48khz
>>
>> 614,4M/13932 = 44.0999khz
> 
> It does not really answer my question though.
> You are locking a use case here, which is 32 bit sample width
> 
> We have other constraint with the upstream audio driver, and we usually
> looking for base frequency that a multiple of 768 (24*32).
> 
> If you need your PLL to be set to a particular rate for a use case, the
> correct way is "assigned-rate" in DT
> 
> so the question still stands, the HIFI pll before was pretty easy to set
> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
> If yes, could you decribe the constraints.
> 
> All this took us a long time to figure out on our own, which is why I'd
> prefer to get the proper constraints in from the beginning this time
> 
ok, I will verify it and  describe the constraints about it
> 
>>
>>>> +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,
>>>> +		},
>>>> +		.table = a1_hifi_pll_params_table,
>>>> +		.init_regs = a1_hifi_init_regs,
>>>> +		.init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "hifi_pll",
>>>> +		.ops = &meson_clk_pcie_pll_ops,
>>>> +		.parent_hws = (const struct clk_hw *[]) {
>>>> +			&a1_xtal_hifipll.hw
>>>> +		},
>>>> +		.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,
>>>> +		/*
>>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>>> +		 * or its children clocks.
>>>> +		 */
>>>
>>> The meaning of this flag is already documented in clk-provider.h
>>> The reason why you need this flag is lot more interesting here ...
>>>
>>> Same below
>> ok, I will replace new comments here.
>>>
>>>> +		.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,
>>>> +		/*
>>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>>> +		 * its children clocks.
>>>> +		 */
>>>> +		.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,
>>>> +		/*
>>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>>> +		 * its children clocks.
>>>> +		 */
>>>> +		.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 = 23,
>>>> +	},
>>>> +	.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,
>>>> +		/*
>>>> +		 * add CLK_IS_CRITICAL flag to avoid being disabled by clk core
>>>> +		 * or its children clock.
>>>> +		 */
>>>> +		.flags = CLK_IS_CRITICAL,
>>>> +	},
>>>> +};
>>>> +
>>>> +/* sys clk = 64M */
>>>
>>> Again this comment does not help understanding the driver code, please
>>> remove
>>>
>> got it.
>>>> +static u32 mux_table_sys_ab_clk[] = { 0, 1, 2, 3};
>>>
>>> This table is useless
>>>
>>>> +static const struct clk_parent_data sys_ab_clk_parent_data[] = {
>>>> +	{ .fw_name = "xtal", },
>>>> +	{ .hw = &a1_fclk_div2.hw },
>>>> +	{ .hw = &a1_fclk_div3.hw },
>>>> +	{ .hw = &a1_fclk_div5.hw },
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_sys_b_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = SYS_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 26,
>>>> +		.table = mux_table_sys_ab_clk,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "sys_b_sel",
>>>> +		.ops = &clk_regmap_mux_ro_ops,
>>>> +		.parent_data = sys_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
>>>
>>> Why does this need to be critical ?
>>> The a1_sys_clk (leaf of the block) could possibly be critical (if you
>>> explain why) ... but the flag should not be needed in the middle of the
>>> block
>>>
>> ok, the a1_sys_clk should not be changed at runtime, it is the same with
>> the clk81 clock in G12A. Just use another name in A1.
> 
> This does not justify the clock to be critical.
> 
> #1 Why can't it be changed ?
> #2 CLK_IS_CRITICAL does not say that clock can't change, it says it
>     can't gate ... two different things
> 
> 
DDR clock's parent clcok is fclk_div2, It can not be gated.I will add
add commits.
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct clk_regmap a1_sys_a_sel = {
>>>> +	.data = &(struct clk_regmap_mux_data){
>>>> +		.offset = SYS_CLK_CTRL0,
>>>> +		.mask = 0x7,
>>>> +		.shift = 10,
>>>> +		.table = mux_table_sys_ab_clk,
>>>> +	},
>>>> +	.hw.init = &(struct clk_init_data){
>>>> +		.name = "sys_a_sel",
>>>> +		.ops = &clk_regmap_mux_ro_ops,
>>>> +		.parent_data = sys_ab_clk_parent_data,
>>>> +		.num_parents = ARRAY_SIZE(sys_ab_clk_parent_data),
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +		.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,
>>>
>>> SET_RATE_PARENT ?
>>>
>> the ops is RO, Maybe no flag is better.
> 
> Is RO for now but setting the rate propagation properly fromt the
> beginning is preferred.
> 
> In general, you should have SET_RATE_PARENT everywhere unless there is a
> reason to stop the rate propagation.
> 
OK, keep SET_RATE_PARENT here
>>>> +	},
>>>> +};
>>>> +
>>>> +/* 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 };
>>>
>>> useless
>>>
>> ok, I will delete the table.
>>>> +
>>>> +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", },
>>>> +	{ .hw = &a1_fclk_div2.hw },
>>>> +	{ .hw = &a1_fclk_div3.hw },
>>>> +	{ .hw = &a1_fclk_div5.hw },
>>>> +	{ .hw = &a1_hifi_pll.hw },
>>>> +	{ .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 | CLK_IGNORE_UNUSED,
>>>
>>> This CLK_IGNORE_UNUSED, if justified, needs to be explained
>>>
>> ok, DSP cowork withe ARM in A1, dsp clock shoud not be changed at
>> runtime.
> 
> #1: UNUSED only guarantee that the clock won't be gated in the late init
>   if. No guarantee whatsoever after that.
> #2: If you have a DSP that need a clock active at particular rate, write
>   a driver for it and use the clock API. Don't throw your use case
>   constraints in the tree def.
> 
> Please review all occurrences of CRITICAL, RO, IGNORE_UNUSED before
> sending a v2.
> 
Yes, Dsp related driver should enable the clock itsself, remove 
CLK_IGNORE_UNUSED
>>>> +	},
>>>> +};
>>>> +
>>>> +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 | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +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_hws = (const struct clk_hw *[]) {
>>>> +			&a1_fclk_div2.hw
>>>> +		},
>>>> +		.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 */
>>>
>>> Either put something helpful or don't put anything
>>> For example explaining why there is a hole in the table bellow and what
>>> is parent 4 (if any) would be helpful.
>> ok, parent 2 is sys_pll_div16, sys pll and related clock are not
>> completeed, parent 4 is one of clock measurement source, it relies on
>> the clock measurement register configuration.
>> gen clock is a debug and monitor clock.
>>>
>>>> +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 },
>>>> +	{ .hw = &a1_hifi_pll.hw },
>>>> +	{ .hw = &a1_fclk_div2.hw },
>>>> +	{ .hw = &a1_fclk_div3.hw },
>>>> +	{ .hw = &a1_fclk_div5.hw },
>>>> +	{ .hw = &a1_fclk_div7.hw },
>>>> +};
>>>> +
>>>> +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 },
>>>> +};
>>>> +
>>>> +/*
>>>> + * add CLK_IGNORE_UNUSED flag for pwm controller GATE
>>>> + * clk core will disable unused clock, it may disable
>>>> + * vddcore voltage which contrlled by one pwm in bl21.
>>>                                ^
>>>                                typo
>>>
>>>> + * add the flag to avoid changing cpu voltage.
>>>
>>> 80 char per line is ok
>>> This comment would be better placed next to the corresponding flag
>>>
>>> Also you could explain that flag could be removed when CCF has some
>>> hand-off mechanism (similar comments you can copy in other driver)
>>>
>> ok,  contrlled --> controlled
>> I will move the comment next to the flag
>> I have gotten the similar comments in g12a.c
>>>> + */
>>>> +/* 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,
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>
>> [...]
>>
>>>> +/* usb bus clk */
>>>> +static const struct clk_parent_data usb_bus_parent_data[] = {
>>>> +	{ .fw_name = "xtal", },
>>>> +	{ .hw = &a1_sys_clk.hw },
>>>> +	{ .hw = &a1_fclk_div3.hw },
>>>> +	{ .hw = &a1_fclk_div5.hw },
>>>> +};
>>>> +
>>>> +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 | CLK_IGNORE_UNUSED,
>>>
>>> Again, every unused flag need to be properly explained
>>>
>> ok, I will confirm this flag
>>>> +	},
>>>> +};
>>>> +
>>>> +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 | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>>> +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 | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>
>> [...]
>>
>>>> +
>>>> +/* dmc clk */
>>>> +static const struct clk_hw *dmc_parent_hws[] = {
>>>> +	&a1_fclk_div2.hw,
>>>> +	&a1_fclk_div3.hw,
>>>> +	&a1_fclk_div5.hw,
>>>> +	&a1_hifi_pll.hw,
>>>> +};
>>>> +
>>>> +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_hws = dmc_parent_hws,
>>>> +		.num_parents = ARRAY_SIZE(dmc_parent_hws),
>>>> +	},
>>>> +};
>>>> +
>>>> +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,
>>>> +		/*
>>>> +		 * add CLK_IGNORE_UNUSED to avoid hangup
>>>> +		 * DDR clock should not change at runtime
>>>> +		 */
>>>
>>> CRITICAL ? RO ops maybe ?
>> RO ops is better
>>>
>>>> +		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>>> +	},
>>>> +};
>>>> +
>>
>> [...]
>>
>>>> +
>>>> +#define MESON_GATE(_name, _reg, _bit) \
>>>> +	MESON_PCLK(_name, _reg, _bit, &a1_sys_clk.hw)
>>>> +
>>>> +/* CLKTREE_SYS_CLK_EN0 */
>>>
>>> Full caps is not ok ... and once again, try to add comment which helps
>> ok, I will add some useful comment.
>>>
>>>> +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);
>>>> +/* CLKTREE_SYS_CLK_EN1 */
>>>> +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);
>>>> +/* CLKTREE_AXI_CLK_EN */
>>>> +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);
>>>> +
>>
>> [...]
>>
>>>> +
>>>> +/* Convenience table to populate regmap in .probe
>>>> + * Peripheral clock register base address is 0xfe000800
>>>
>>> this info will be in DT
>> I will remove the address commit
>>>
>>>> + */
>>
>> [...]
>>
>>>> +
>>>> +/*
>>>> + * cpu clock register base address is 0xfd000080
>>>> + */
>>>> +static struct clk_regmap *const a1_cpu_clk_regmaps[] = {
>>>> +	/* TODO */
>>>> +};
>>>> +
>>>> +/*
>>>> + * pll clock register base address is 0xfe007c00
>>>> + */
>>>> +static struct clk_regmap *const a1_pll_clk_regmaps[] = {
>>>> +	&a1_fixed_pll_dco,
>>>> +	&a1_fixed_pll,
>>>> +	&a1_hifi_pll,
>>>> +	&a1_fclk_div2,
>>>> +	&a1_fclk_div3,
>>>> +	&a1_fclk_div5,
>>>> +	&a1_fclk_div7,
>>>> +};
>>>> +
>>>> +static struct regmap_config clkc_regmap_config = {
>>>> +	.reg_bits       = 32,
>>>> +	.val_bits       = 32,
>>>> +	.reg_stride     = 4,
>>>> +};
>>>> +
>>>> +static struct regmap *a1_regmap_resource(struct device *dev, char *name)
>>>> +{
>>>> +	struct resource res;
>>>> +	void __iomem *base;
>>>> +	int i;
>>>> +	struct device_node *node = dev->of_node;
>>>> +
>>>> +	i = of_property_match_string(node, "reg-names", name);
>>>> +	if (of_address_to_resource(node, i, &res))
>>>> +		return ERR_PTR(-ENOENT);
>>>> +
>>>> +	base = devm_ioremap_resource(dev, &res);
>>>> +	if (IS_ERR(base))
>>>> +		return ERR_CAST(base);
>>>> +
>>>> +	clkc_regmap_config.max_register = resource_size(&res) - 4;
>>>> +	clkc_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
>>>> +						 "%s-%s", node->name,
>>>> +						 name);
>>>> +	if (!clkc_regmap_config.name)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	return devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
>>>> +}
>>>> +
>>>> +static int a1_clkc_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct regmap *peripheral_map, *pll_map, *cpu_map;
>>>> +	int ret, i;
>>>> +
>>>> +	/* Get regmap for different clock area */
>>>> +	peripheral_map = a1_regmap_resource(dev, "peripheral");
>>>> +	if (IS_ERR(peripheral_map)) {
>>>> +		dev_err(dev, "peripheral clk registers not found\n");
>>>> +		return PTR_ERR(peripheral_map);
>>>> +	}
>>>> +
>>>> +	pll_map = a1_regmap_resource(dev, "pll");
>>>> +	if (IS_ERR(pll_map)) {
>>>> +		dev_err(dev, "pll clk registers not found\n");
>>>> +		return PTR_ERR(pll_map);
>>>> +	}
>>>> +
>>>> +	cpu_map = a1_regmap_resource(dev, "cpu");
>>>> +	if (IS_ERR(cpu_map)) {
>>>> +		dev_err(dev, "cpu clk registers not found\n");
>>>> +		return PTR_ERR(cpu_map);
>>>> +	}
>>>> +
>>>> +	/* Populate regmap for the regmap backed clocks */
>>>> +	for (i = 0; i < ARRAY_SIZE(a1_clk_regmaps); i++)
>>>> +		a1_clk_regmaps[i]->map = peripheral_map;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(a1_cpu_clk_regmaps); i++)
>>>> +		a1_cpu_clk_regmaps[i]->map = cpu_map;
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(a1_pll_clk_regmaps); i++)
>>>> +		a1_pll_clk_regmaps[i]->map = pll_map;
>>>
>>> Unless you have a rock solid reason why you absolutely need to make
>>> single controller out of this 3 regions, Nack.
>>>
>> As comment replying in
>> Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml, I will
>> implement three clock drivers.
>>>> +
>>>> +	for (i = 0; i < a1_hw_onecell_data.num; i++) {
>>>> +		/* array might be sparse */
>>>> +		if (!a1_hw_onecell_data.hws[i])
>>>> +			continue;
>>>> +
>>>> +		ret = devm_clk_hw_register(dev, a1_hw_onecell_data.hws[i]);
>>>> +		if (ret) {
>>>> +			dev_err(dev, "Clock registration failed\n");
>>>> +			return ret;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
>>>> +					   &a1_hw_onecell_data);
>>>> +}
>>>> +
>>>> +static const struct of_device_id clkc_match_table[] = {
>>>> +	{ .compatible = "amlogic,a1-clkc" },
>>>> +	{ /* sentinel */ }
>>>> +};
>>>> +
>>>> +static struct platform_driver a1_driver = {
>>>> +	.probe		= a1_clkc_probe,
>>>> +	.driver		= {
>>>> +		.name	= "a1-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..f2291c4
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a1.h
>>>> @@ -0,0 +1,172 @@
>>>> +/* 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 address
>>>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe000800
>>>
>>> Again this info is DT and might become wrong if your controller is ever
>>> compatible with another SoC
>>>
>> I will remove the address comment, the right address is 0xfe000080.
>>>> + */
>>>> +#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
>>>> +/*
>>>> + * For PLL register offset
>>>> + * APB_BASE:  APB0_BASE_ADDR = 0xfe007c00
>>>> + */
>>>> +#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
>>>> +/*
>>>> + * CPU clok register offset
>>>> + * APB_BASE:  APB1_BASE_ADDR = 0xfd000080
>>>> + */
>>>> +#define CPUCTRL_CLK_CTRL0		0x00
>>>> +#define CPUCTRL_CLK_CTRL1		0x04
>>>> +#define CPUCTRL_CLK_CTRL2		0x08
>>>> +#define CPUCTRL_CLK_CTRL3		0x0c
>>>> +#define CPUCTRL_CLK_CTRL4		0x10
>>>> +#define CPUCTRL_CLK_CTRL5		0x14
>>>> +#define CPUCTRL_CLK_CTRL6		0x18
>>>> +#define CPUCTRL_CLK_CTRL7		0x1c
>>>> +
>>>> +#define CLKID_FIXED_PLL_DCO		0
>>>> +#define CLKID_SYS_A_SEL			10
>>>> +#define CLKID_SYS_A_DIV			11
>>>> +#define CLKID_SYS_A			12
>>>> +#define CLKID_SYS_B_SEL			13
>>>> +#define CLKID_SYS_B_DIV			14
>>>> +#define CLKID_SYS_B			15
>>>> +#define CLKID_XTAL_CLKTREE		18
>>>> +#define CLKID_XTAL_FIXPLL		19
>>>> +#define CLKID_XTAL_USB_PHY		20
>>>> +#define CLKID_XTAL_USB_CTRL		21
>>>> +#define CLKID_XTAL_HIFIPLL		22
>>>> +#define CLKID_XTAL_SYSPLL		23
>>>> +#define CLKID_XTAL_DDS			24
>>>> +#define CLKID_DSPA_A_SEL		78
>>>> +#define CLKID_DSPA_A_DIV		79
>>>> +#define CLKID_DSPA_A			80
>>>> +#define CLKID_DSPA_B_SEL		81
>>>> +#define CLKID_DSPA_B_DIV		82
>>>> +#define CLKID_DSPA_B			83
>>>> +#define CLKID_DSPB_A_SEL		85
>>>> +#define CLKID_DSPB_A_DIV		86
>>>> +#define CLKID_DSPB_A			87
>>>> +#define CLKID_DSPB_B_SEL		88
>>>> +#define CLKID_DSPB_B_DIV		89
>>>> +#define CLKID_DSPB_B			90
>>>> +#define CLKID_RTC_32K_CLKIN		96
>>>> +#define CLKID_RTC_32K_DIV		97
>>>> +#define CLKID_RTC_32K_XTAL		98
>>>> +#define CLKID_RTC_32K_SEL		99
>>>> +#define CLKID_CECB_32K_CLKIN		106
>>>> +#define CLKID_CECB_32K_DIV		107
>>>> +#define CLKID_CECB_32K_SEL_PRE		108
>>>> +#define CLKID_CECB_32K_SEL		109
>>>> +#define CLKID_CECA_32K_CLKIN		101
>>>> +#define CLKID_CECA_32K_DIV		102
>>>> +#define CLKID_CECA_32K_SEL_PRE		103
>>>> +#define CLKID_CECA_32K_SEL		104
>>>> +#define CLKID_DIV2_PRE			113
>>>> +#define CLKID_24M_DIV2			115
>>>> +#define CLKID_GEN_SEL			116
>>>> +#define CLKID_GEN_DIV			117
>>>> +#define CLKID_SARADC_DIV		120
>>>> +#define CLKID_PWM_A_SEL			122
>>>> +#define CLKID_PWM_A_DIV			123
>>>> +#define CLKID_PWM_B_SEL			125
>>>> +#define CLKID_PWM_B_DIV			126
>>>> +#define CLKID_PWM_C_SEL			128
>>>> +#define CLKID_PWM_C_DIV			129
>>>> +#define CLKID_PWM_D_SEL			131
>>>> +#define CLKID_PWM_D_DIV			132
>>>> +#define CLKID_PWM_E_SEL			134
>>>> +#define CLKID_PWM_E_DIV			135
>>>> +#define CLKID_PWM_F_SEL			137
>>>> +#define CLKID_PWM_F_DIV			138
>>>> +#define CLKID_SPICC_SEL			140
>>>> +#define CLKID_SPICC_DIV			141
>>>> +#define CLKID_SPICC_SEL2		142
>>>> +#define CLKID_TS_DIV			144
>>>> +#define CLKID_SPIFC_SEL			146
>>>> +#define CLKID_SPIFC_DIV			147
>>>> +#define CLKID_SPIFC_SEL2		148
>>>> +#define CLKID_USB_BUS_SEL		150
>>>> +#define CLKID_USB_BUS_DIV		151
>>>> +#define CLKID_SD_EMMC_SEL		153
>>>> +#define CLKID_SD_EMMC_DIV		154
>>>> +#define CLKID_SD_EMMC_SEL2		155
>>>> +#define CLKID_PSRAM_SEL			157
>>>> +#define CLKID_PSRAM_DIV			158
>>>> +#define CLKID_PSRAM_SEL2		159
>>>> +#define CLKID_DMC_SEL			161
>>>> +#define CLKID_DMC_DIV			162
>>>> +#define CLKID_DMC_SEL2			163
>>>> +#define NR_CLKS				165
>>>> +
>>>> +#include <dt-bindings/clock/a1-clkc.h>
>>>> +
>>>> +#endif /* __A1_H */
>>>> -- 
>>>> 1.9.1
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-09-29  9:38         ` Jian Hu
@ 2019-10-08  8:03           ` Jian Hu
  2019-10-11  7:39             ` Jerome Brunet
  0 siblings, 1 reply; 20+ messages in thread
From: Jian Hu @ 2019-10-08  8:03 UTC (permalink / raw)
  To: Jerome Brunet
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Rob Herring,
	Martin Blumenstingl, Michael Turquette, Stephen Boyd,
	Qiufang Dai, linux-clk, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

Hi, Jerome

PLL clocks and peripheral clocks rely on each other.

for fixed_pll, we can describe its parent like this:

xtal-->xtal_fixpll-->fixed_dco-->fixed_pll

xtal fixpll is belong to peripheral region.
fixed_pll/fclk_div2/fclk_div3 is belong to PLL region.

if PLL clocks probe first, it will fail to get xtal_fixpll.
we can not get fixed_dco's parent clock.

if peripheral clocks probe first, it will fail to get
fixed_pll clocks. A lot of peripheral clocks parent are fclk_div2/3/5/7.
and we can not get fclk_div2/3/5/7 clocks.

I can think of two solutions:
1) Do not describe xtal_fixpll, xtal_hifipll.
    that is to say, do not decribe the SYS_OSCIN_CTRL register.

2) Put peripheral and pll clock driver in one driver.

And  which sulution is better above two?

Or maybe other good ideas for it?

On 2019/9/29 17:38, Jian Hu wrote:
> 
> 
> On 2019/9/27 21:32, Jerome Brunet wrote:
>>
>> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
>>
>>> Hi, Jerome
>>>
>>> Thank you for review.
>>>
>>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> The Amlogic A1 clock includes three parts:
>>>>> 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>
>>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>>> ---
>>>>>    arch/arm64/Kconfig.platforms |    1 +
>>>>>    drivers/clk/meson/Kconfig    |   10 +
>>>>>    drivers/clk/meson/Makefile   |    1 +
>>>>>    drivers/clk/meson/a1.c       | 2617 
>>>>> ++++++++++++++++++++++++++++++++++++++++++
>>>>>    drivers/clk/meson/a1.h       |  172 +++
>>>>>    5 files changed, 2801 insertions(+)
>>>>>    create mode 100644 drivers/clk/meson/a1.c
>>>>>    create mode 100644 drivers/clk/meson/a1.h
>>>>>
[...]
>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>> new file mode 100644
>>>>> index 0000000..26edae0f
>>>>> --- /dev/null
>>>>> +++ b/drivers/clk/meson/a1.c
>>>>> @@ -0,0 +1,2617 @@
>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>> +/*
>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>> + */
>>>>> +
>>>>> +#include <linux/clk-provider.h>
>>>>> +#include <linux/init.h>
>>>>> +#include <linux/of_device.h>
>>>>> +#include <linux/platform_device.h>
>>>>> +#include <linux/of_address.h>
>>>>> +#include "clk-mpll.h"
>>>>> +#include "clk-pll.h"
>>>>> +#include "clk-regmap.h"
>>>>> +#include "vid-pll-div.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_ops,
>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>> +            .fw_name = "xtal",
>>>>> +        },
>>>>> +        .num_parents = 1,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>
>>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>>> Please review your other clocks with this in mind
>>>>
>>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>>> +    },
>>>>> +};
>>>>> +
>>>>> +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,
>>>>> +    },
>>>>> +};
>>>>> +
>>>>> +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,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>
>>>> How is an USB clock critical to the system ?
>>>> Please review your other clocks with comment in mind ...
>>> the usb clock does not affect the system,
>>> remove the CLK_IS_CRITICAL flag
>>>>
>>>>> +    },
>>>>> +};
>>>>> +
>>>>> +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,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>> +    },
>>>>> +};
>>> the usb clock does not affect the system,
>>> remove the CLK_IS_CRITICAL flag
>>>>> +
>>>>> +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,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>> +    },
>>>>> +};
>>> CLK_IS_CRITICAL is need to lock hifi pll.
>>
>> That's not how CCF works, this falg is not ok here.
>> CCF will enable this clock before calling enable on your hifi pll
>>
> ok, I will remove it.
>>>>> +
>>>>> +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,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>> +    },
>>>>> +};
>>>>> +
>>> when CPU clock is at fixed clock, sys pll
>>> will be disabled, xtal_syspll will be disabled too.
>>> when setting sys pll, call clk_set_rate to lock
>>> sys pll, add RO ops to avoid disabling the clock
>>
>> Again not Ok.
>> If you mechanism to lock the PLL is properly implemented in the enable
>> callback of the sys pll, still kind of work around are not needed
>>
>> This has worked on the pll we had so far.
>>
> ok, I will remove it.
>>>
>>>>> +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,
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>> +    },
>>>>> +};
>>> CLK_IS_CRITICAL is need to lock dds
>>>>> +
>>>>> +/* fixed pll = 1536M
>>>>> + *
>>>>> + * fixed pll ----- fclk_div2 = 768M
>>>>> + *           |
>>>>> + *           ----- fclk_div3 = 512M
>>>>> + *           |
>>>>> + *           ----- fclk_div5 = 307.2M
>>>>> + *           |
>>>>> + *           ----- fclk_div7 = 219.4M
>>>>> + */
>>>>
>>>> The framework will make those calculation ... you can remove this
>>>>
>>> ok, I will remote the comment.
>>>>> +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_hws = (const struct clk_hw *[]) {
>>>>> +            &a1_xtal_fixpll.hw
>>>>> +        },
>>>>> +        .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,
>>>>> +        .flags = CLK_IGNORE_UNUSED,
>>>>> +    },
>>>>> +};
>>>>> +
>>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>>> +    PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>>> +};
>>>>> +
>>>>> +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 = 0x10022200 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4,    .def = 0x00301000 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us = 
>>>>> 10 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0,    .def = 0x15f11480, 
>>>>> .delay_us = 40 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001140 },
>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001100 },
>>>>> +};
>>>>> +
>>>>> +/*
>>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>>> + * a strict register sequence to enable the PLL.
>>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>>> + */
>>>>
>>>> Could you elaborate on this ? What need to be done to enable the 
>>>> clock ?
>>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>>> might be desirable for audio use case. Why is this one restricted to 
>>>> one
>>>> particular rate ?
>>>>
>>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>>
>>> 614.4M can meet the three frequency.
>>>
>>> after the hifi pll, there are two dividers in Audio clock.
>>>
>>> 614.4M/3200 = 192khz
>>>
>>> 614.4M/12800 = 48khz
>>>
>>> 614,4M/13932 = 44.0999khz
>>
>> It does not really answer my question though.
>> You are locking a use case here, which is 32 bit sample width
>>
>> We have other constraint with the upstream audio driver, and we usually
>> looking for base frequency that a multiple of 768 (24*32).
>>
>> If you need your PLL to be set to a particular rate for a use case, the
>> correct way is "assigned-rate" in DT
>>
>> so the question still stands, the HIFI pll before was pretty easy to set
>> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
>> If yes, could you decribe the constraints.
>>
>> All this took us a long time to figure out on our own, which is why I'd
>> prefer to get the proper constraints in from the beginning this time
>>
> ok, I will verify it and  describe the constraints about it
>>
>>>
>>>>> +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,
>>>>> +        },
>>>>> +        .table = a1_hifi_pll_params_table,
>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>> +    },
>>>>> +    .hw.init = &(struct clk_init_data){
>>>>> +        .name = "hifi_pll",
>>>>> +        .ops = &meson_clk_pcie_pll_ops,
>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>> +            &a1_xtal_hifipll.hw
>>>>> +        },
>>>>> +        .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,
>>>>> +        /*
>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk 
>>>>> core
>>>>> +         * or its children clocks.
>>>>> +         */
>>>>
>>>> The meaning of this flag is already documented in clk-provider.h
>>>> The reason why you need this flag is lot more interesting here ...
>>>>
>>>> Same below
>>> ok, I will replace new comments here.
>>>>
>>>>> +        .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,
>>>>> +        /*
>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk 
>>>>> core
>>>>> +         * its children clocks.
>>>>> +         */
>>>>> +        .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,
>>>>> +        /*
>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk 
>>>>> core
>>>>> +         * its children clocks.
>>>>> +         */
>>>>> +        .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 = 23,
>>>>> +    },
>>>>> +    .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,
>>>>> +        /*
>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk 
>>>>> core
>>>>> +         * or its children clock.
>>>>> +         */
>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>> +    },
>>>>> +};
>>>>> +
[...]
>>>>> -- 
>>>>> 1.9.1
>>>>
>>>> .
>>>>
>>
>> .
>>

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-08  8:03           ` Jian Hu
@ 2019-10-11  7:39             ` Jerome Brunet
  2019-10-14 13:42               ` Jian Hu
  0 siblings, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-10-11  7:39 UTC (permalink / raw)
  To: Jian Hu, Stephen Boyd
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Martin Blumenstingl,
	Michael Turquette, Qiufang Dai, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree


On Tue 08 Oct 2019 at 10:03, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi, Jerome
>
> PLL clocks and peripheral clocks rely on each other.
>
> for fixed_pll, we can describe its parent like this:
>
> xtal-->xtal_fixpll-->fixed_dco-->fixed_pll
>
> xtal fixpll is belong to peripheral region.
> fixed_pll/fclk_div2/fclk_div3 is belong to PLL region.
>
> if PLL clocks probe first, it will fail to get xtal_fixpll.
> we can not get fixed_dco's parent clock.
>
> if peripheral clocks probe first, it will fail to get
> fixed_pll clocks. A lot of peripheral clocks parent are fclk_div2/3/5/7.
> and we can not get fclk_div2/3/5/7 clocks.

What does "fail" mean ?

>
> I can think of two solutions:
> 1) Do not describe xtal_fixpll, xtal_hifipll.
>    that is to say, do not decribe the SYS_OSCIN_CTRL register.
>
> 2) Put peripheral and pll clock driver in one driver.

Those are work arounds. Actually fixing the problem is usually
preferable.

 So if rephrase your problem:

 * We have 2 clock controllers (A and B)
 * Clock are passed between the controllers using DT
 * We have a PLL in controller B which is used by clocks in
   controller A.
 * the PLL parent clock is in controller A.

=> So if I understand correctly you are saying that it will "fail"
because there is a circular dependency between controller A and B, right
?

Do you have evidence that your problem comes from this circular
dependency ?

AFAIK, CCF will orphan the clock and continue if the parent is not
available. Later, when the parent comes up, the orphan will be
reparented.

IOW, the problem you are reporting should already be covered by CCF.

>
> And  which sulution is better above two?

Neither, I'm afraid

>
> Or maybe other good ideas for it?

My bet would be that an important clocks (maybe more than 1) is being
gated during the init process.

Maybe you should try the command line parameter "clk_ignore_unused"
until you get things running with your 2 controllers.

>
> On 2019/9/29 17:38, Jian Hu wrote:
>>
>>
>> On 2019/9/27 21:32, Jerome Brunet wrote:
>>>
>>> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
>>>
>>>> Hi, Jerome
>>>>
>>>> Thank you for review.
>>>>
>>>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>
>>>>>> The Amlogic A1 clock includes three parts:
>>>>>> 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>
>>>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>>>> ---
>>>>>>    arch/arm64/Kconfig.platforms |    1 +
>>>>>>    drivers/clk/meson/Kconfig    |   10 +
>>>>>>    drivers/clk/meson/Makefile   |    1 +
>>>>>>    drivers/clk/meson/a1.c       | 2617
>>>>>> ++++++++++++++++++++++++++++++++++++++++++
>>>>>>    drivers/clk/meson/a1.h       |  172 +++
>>>>>>    5 files changed, 2801 insertions(+)
>>>>>>    create mode 100644 drivers/clk/meson/a1.c
>>>>>>    create mode 100644 drivers/clk/meson/a1.h
>>>>>>
> [...]
>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>> new file mode 100644
>>>>>> index 0000000..26edae0f
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>> @@ -0,0 +1,2617 @@
>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>> +/*
>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/clk-provider.h>
>>>>>> +#include <linux/init.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> +#include <linux/platform_device.h>
>>>>>> +#include <linux/of_address.h>
>>>>>> +#include "clk-mpll.h"
>>>>>> +#include "clk-pll.h"
>>>>>> +#include "clk-regmap.h"
>>>>>> +#include "vid-pll-div.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_ops,
>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>> +            .fw_name = "xtal",
>>>>>> +        },
>>>>>> +        .num_parents = 1,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>
>>>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>>>> Please review your other clocks with this in mind
>>>>>
>>>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>>>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>>>> +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,
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>>>> +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,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>
>>>>> How is an USB clock critical to the system ?
>>>>> Please review your other clocks with comment in mind ...
>>>> the usb clock does not affect the system,
>>>> remove the CLK_IS_CRITICAL flag
>>>>>
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>>>> +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,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>> +    },
>>>>>> +};
>>>> the usb clock does not affect the system,
>>>> remove the CLK_IS_CRITICAL flag
>>>>>> +
>>>>>> +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,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>> +    },
>>>>>> +};
>>>> CLK_IS_CRITICAL is need to lock hifi pll.
>>>
>>> That's not how CCF works, this falg is not ok here.
>>> CCF will enable this clock before calling enable on your hifi pll
>>>
>> ok, I will remove it.
>>>>>> +
>>>>>> +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,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>> when CPU clock is at fixed clock, sys pll
>>>> will be disabled, xtal_syspll will be disabled too.
>>>> when setting sys pll, call clk_set_rate to lock
>>>> sys pll, add RO ops to avoid disabling the clock
>>>
>>> Again not Ok.
>>> If you mechanism to lock the PLL is properly implemented in the enable
>>> callback of the sys pll, still kind of work around are not needed
>>>
>>> This has worked on the pll we had so far.
>>>
>> ok, I will remove it.
>>>>
>>>>>> +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,
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>> +    },
>>>>>> +};
>>>> CLK_IS_CRITICAL is need to lock dds
>>>>>> +
>>>>>> +/* fixed pll = 1536M
>>>>>> + *
>>>>>> + * fixed pll ----- fclk_div2 = 768M
>>>>>> + *           |
>>>>>> + *           ----- fclk_div3 = 512M
>>>>>> + *           |
>>>>>> + *           ----- fclk_div5 = 307.2M
>>>>>> + *           |
>>>>>> + *           ----- fclk_div7 = 219.4M
>>>>>> + */
>>>>>
>>>>> The framework will make those calculation ... you can remove this
>>>>>
>>>> ok, I will remote the comment.
>>>>>> +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_hws = (const struct clk_hw *[]) {
>>>>>> +            &a1_xtal_fixpll.hw
>>>>>> +        },
>>>>>> +        .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,
>>>>>> +        .flags = CLK_IGNORE_UNUSED,
>>>>>> +    },
>>>>>> +};
>>>>>> +
>>>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>>>> +    PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>>>> +};
>>>>>> +
>>>>>> +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 = 0x10022200 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4,    .def = 0x00301000 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us =
>>>>>> 10 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0,    .def = 0x15f11480, .delay_us
>>>>>> = 40 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001140 },
>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001100 },
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>>>> + * a strict register sequence to enable the PLL.
>>>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>>>> + */
>>>>>
>>>>> Could you elaborate on this ? What need to be done to enable the clock
>>>>> ?
>>>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>>>> might be desirable for audio use case. Why is this one restricted to
>>>>> one
>>>>> particular rate ?
>>>>>
>>>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>>>
>>>> 614.4M can meet the three frequency.
>>>>
>>>> after the hifi pll, there are two dividers in Audio clock.
>>>>
>>>> 614.4M/3200 = 192khz
>>>>
>>>> 614.4M/12800 = 48khz
>>>>
>>>> 614,4M/13932 = 44.0999khz
>>>
>>> It does not really answer my question though.
>>> You are locking a use case here, which is 32 bit sample width
>>>
>>> We have other constraint with the upstream audio driver, and we usually
>>> looking for base frequency that a multiple of 768 (24*32).
>>>
>>> If you need your PLL to be set to a particular rate for a use case, the
>>> correct way is "assigned-rate" in DT
>>>
>>> so the question still stands, the HIFI pll before was pretty easy to set
>>> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
>>> If yes, could you decribe the constraints.
>>>
>>> All this took us a long time to figure out on our own, which is why I'd
>>> prefer to get the proper constraints in from the beginning this time
>>>
>> ok, I will verify it and  describe the constraints about it
>>>
>>>>
>>>>>> +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,
>>>>>> +        },
>>>>>> +        .table = a1_hifi_pll_params_table,
>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>> +    },
>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>> +        .name = "hifi_pll",
>>>>>> +        .ops = &meson_clk_pcie_pll_ops,
>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>> +            &a1_xtal_hifipll.hw
>>>>>> +        },
>>>>>> +        .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,
>>>>>> +        /*
>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>> core
>>>>>> +         * or its children clocks.
>>>>>> +         */
>>>>>
>>>>> The meaning of this flag is already documented in clk-provider.h
>>>>> The reason why you need this flag is lot more interesting here ...
>>>>>
>>>>> Same below
>>>> ok, I will replace new comments here.
>>>>>
>>>>>> +        .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,
>>>>>> +        /*
>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>> core
>>>>>> +         * its children clocks.
>>>>>> +         */
>>>>>> +        .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,
>>>>>> +        /*
>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>> core
>>>>>> +         * its children clocks.
>>>>>> +         */
>>>>>> +        .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 = 23,
>>>>>> +    },
>>>>>> +    .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,
>>>>>> +        /*
>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>> core
>>>>>> +         * or its children clock.
>>>>>> +         */
>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>> +    },
>>>>>> +};
>>>>>> +
> [...]
>>>>>> -- 
>>>>>> 1.9.1
>>>>>
>>>>> .
>>>>>
>>>
>>> .
>>>


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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-11  7:39             ` Jerome Brunet
@ 2019-10-14 13:42               ` Jian Hu
  2019-10-14 14:55                 ` Jerome Brunet
  0 siblings, 1 reply; 20+ messages in thread
From: Jian Hu @ 2019-10-14 13:42 UTC (permalink / raw)
  To: Jerome Brunet, Stephen Boyd
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Martin Blumenstingl,
	Michael Turquette, Qiufang Dai, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

Hi, Jerome

sorry, it's my problem.

I did not discribe clearly the issue.

On 2019/10/11 15:39, Jerome Brunet wrote:
> 
> On Tue 08 Oct 2019 at 10:03, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>> Hi, Jerome
>>
>> PLL clocks and peripheral clocks rely on each other.
>>
>> for fixed_pll, we can describe its parent like this:
>>
>> xtal-->xtal_fixpll-->fixed_dco-->fixed_pll
>>
>> xtal fixpll is belong to peripheral region.
>> fixed_pll/fclk_div2/fclk_div3 is belong to PLL region.
>>
>> if PLL clocks probe first, it will fail to get xtal_fixpll.
>> we can not get fixed_dco's parent clock.
>>
>> if peripheral clocks probe first, it will fail to get
>> fixed_pll clocks. A lot of peripheral clocks parent are fclk_div2/3/5/7.
>> and we can not get fclk_div2/3/5/7 clocks.
> 
> What does "fail" mean ?
> I intended to get clock using devm_clk_get API in each driver, In this 
scene,it will get failed because of the clock not being reigstered. In 
fact, we could not use devm_clk_get.
>>
>> I can think of two solutions:
>> 1) Do not describe xtal_fixpll, xtal_hifipll.
>>     that is to say, do not decribe the SYS_OSCIN_CTRL register.
>>
>> 2) Put peripheral and pll clock driver in one driver.
> 
> Those are work arounds. Actually fixing the problem is usually
> preferable.
> 
>   So if rephrase your problem:
> 
>   * We have 2 clock controllers (A and B)
>   * Clock are passed between the controllers using DT
>   * We have a PLL in controller B which is used by clocks in
>     controller A.
>   * the PLL parent clock is in controller A.
> 
Yeah, it is the scene.
> => So if I understand correctly you are saying that it will "fail"
> because there is a circular dependency between controller A and B, right
> ?
> 
> Do you have evidence that your problem comes from this circular
> dependency ?
> 
I have realized the peripheral driver and PLL drivers,

PLL driver probes first, Peripheral clock driver is the second.

In addition,for A1 SoC, it will not work using meson_clk_pll_ops,

it needs strictly sequence,so maybe another ops is required.hifi pll 
will be sent with sys pll and CPU clock driver.
> AFAIK, CCF will orphan the clock and continue if the parent is not
> available. Later, when the parent comes up, the orphan will be
> reparented.
> 
> IOW, the problem you are reporting should already be covered by CCF.
> 
>>
>> And  which sulution is better above two?
> 
> Neither, I'm afraid
> 
>>
>> Or maybe other good ideas for it?
> 
> My bet would be that an important clocks (maybe more than 1) is being
> gated during the init process.
> 
> Maybe you should try the command line parameter "clk_ignore_unused"
> until you get things running with your 2 controllers.
> 
>>
>> On 2019/9/29 17:38, Jian Hu wrote:
>>>
>>>
>>> On 2019/9/27 21:32, Jerome Brunet wrote:
>>>>
>>>> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>
>>>>> Hi, Jerome
>>>>>
>>>>> Thank you for review.
>>>>>
>>>>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>>>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>
>>>>>>> The Amlogic A1 clock includes three parts:
>>>>>>> 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>
>>>>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>>>>> ---
>>>>>>>     arch/arm64/Kconfig.platforms |    1 +
>>>>>>>     drivers/clk/meson/Kconfig    |   10 +
>>>>>>>     drivers/clk/meson/Makefile   |    1 +
>>>>>>>     drivers/clk/meson/a1.c       | 2617
>>>>>>> ++++++++++++++++++++++++++++++++++++++++++
>>>>>>>     drivers/clk/meson/a1.h       |  172 +++
>>>>>>>     5 files changed, 2801 insertions(+)
>>>>>>>     create mode 100644 drivers/clk/meson/a1.c
>>>>>>>     create mode 100644 drivers/clk/meson/a1.h
>>>>>>>
>> [...]
>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..26edae0f
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>> @@ -0,0 +1,2617 @@
>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <linux/clk-provider.h>
>>>>>>> +#include <linux/init.h>
>>>>>>> +#include <linux/of_device.h>
>>>>>>> +#include <linux/platform_device.h>
>>>>>>> +#include <linux/of_address.h>
>>>>>>> +#include "clk-mpll.h"
>>>>>>> +#include "clk-pll.h"
>>>>>>> +#include "clk-regmap.h"
>>>>>>> +#include "vid-pll-div.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_ops,
>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>> +            .fw_name = "xtal",
>>>>>>> +        },
>>>>>>> +        .num_parents = 1,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>
>>>>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>>>>> Please review your other clocks with this in mind
>>>>>>
>>>>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>>>>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +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,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +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,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>
>>>>>> How is an USB clock critical to the system ?
>>>>>> Please review your other clocks with comment in mind ...
>>>>> the usb clock does not affect the system,
>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +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,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>> the usb clock does not affect the system,
>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>> +
>>>>>>> +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,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>> CLK_IS_CRITICAL is need to lock hifi pll.
>>>>
>>>> That's not how CCF works, this falg is not ok here.
>>>> CCF will enable this clock before calling enable on your hifi pll
>>>>
>>> ok, I will remove it.
>>>>>>> +
>>>>>>> +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,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>> when CPU clock is at fixed clock, sys pll
>>>>> will be disabled, xtal_syspll will be disabled too.
>>>>> when setting sys pll, call clk_set_rate to lock
>>>>> sys pll, add RO ops to avoid disabling the clock
>>>>
>>>> Again not Ok.
>>>> If you mechanism to lock the PLL is properly implemented in the enable
>>>> callback of the sys pll, still kind of work around are not needed
>>>>
>>>> This has worked on the pll we had so far.
>>>>
>>> ok, I will remove it.
>>>>>
>>>>>>> +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,
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>> CLK_IS_CRITICAL is need to lock dds
>>>>>>> +
>>>>>>> +/* fixed pll = 1536M
>>>>>>> + *
>>>>>>> + * fixed pll ----- fclk_div2 = 768M
>>>>>>> + *           |
>>>>>>> + *           ----- fclk_div3 = 512M
>>>>>>> + *           |
>>>>>>> + *           ----- fclk_div5 = 307.2M
>>>>>>> + *           |
>>>>>>> + *           ----- fclk_div7 = 219.4M
>>>>>>> + */
>>>>>>
>>>>>> The framework will make those calculation ... you can remove this
>>>>>>
>>>>> ok, I will remote the comment.
>>>>>>> +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_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_xtal_fixpll.hw
>>>>>>> +        },
>>>>>>> +        .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,
>>>>>>> +        .flags = CLK_IGNORE_UNUSED,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>>>>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>>>>> +    PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>>>>> +};
>>>>>>> +
>>>>>>> +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 = 0x10022200 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4,    .def = 0x00301000 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us =
>>>>>>> 10 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0,    .def = 0x15f11480, .delay_us
>>>>>>> = 40 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001140 },
>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001100 },
>>>>>>> +};
>>>>>>> +
>>>>>>> +/*
>>>>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>>>>> + * a strict register sequence to enable the PLL.
>>>>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>>>>> + */
>>>>>>
>>>>>> Could you elaborate on this ? What need to be done to enable the clock
>>>>>> ?
>>>>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>>>>> might be desirable for audio use case. Why is this one restricted to
>>>>>> one
>>>>>> particular rate ?
>>>>>>
>>>>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>>>>
>>>>> 614.4M can meet the three frequency.
>>>>>
>>>>> after the hifi pll, there are two dividers in Audio clock.
>>>>>
>>>>> 614.4M/3200 = 192khz
>>>>>
>>>>> 614.4M/12800 = 48khz
>>>>>
>>>>> 614,4M/13932 = 44.0999khz
>>>>
>>>> It does not really answer my question though.
>>>> You are locking a use case here, which is 32 bit sample width
>>>>
>>>> We have other constraint with the upstream audio driver, and we usually
>>>> looking for base frequency that a multiple of 768 (24*32).
>>>>
>>>> If you need your PLL to be set to a particular rate for a use case, the
>>>> correct way is "assigned-rate" in DT
>>>>
>>>> so the question still stands, the HIFI pll before was pretty easy to set
>>>> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
>>>> If yes, could you decribe the constraints.
>>>>
>>>> All this took us a long time to figure out on our own, which is why I'd
>>>> prefer to get the proper constraints in from the beginning this time
>>>>
>>> ok, I will verify it and  describe the constraints about it
>>>>
>>>>>
>>>>>>> +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,
>>>>>>> +        },
>>>>>>> +        .table = a1_hifi_pll_params_table,
>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>> +    },
>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>> +        .name = "hifi_pll",
>>>>>>> +        .ops = &meson_clk_pcie_pll_ops,
>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>> +            &a1_xtal_hifipll.hw
>>>>>>> +        },
>>>>>>> +        .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,
>>>>>>> +        /*
>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>> core
>>>>>>> +         * or its children clocks.
>>>>>>> +         */
>>>>>>
>>>>>> The meaning of this flag is already documented in clk-provider.h
>>>>>> The reason why you need this flag is lot more interesting here ...
>>>>>>
>>>>>> Same below
>>>>> ok, I will replace new comments here.
>>>>>>
>>>>>>> +        .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,
>>>>>>> +        /*
>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>> core
>>>>>>> +         * its children clocks.
>>>>>>> +         */
>>>>>>> +        .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,
>>>>>>> +        /*
>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>> core
>>>>>>> +         * its children clocks.
>>>>>>> +         */
>>>>>>> +        .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 = 23,
>>>>>>> +    },
>>>>>>> +    .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,
>>>>>>> +        /*
>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>> core
>>>>>>> +         * or its children clock.
>>>>>>> +         */
>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>> +    },
>>>>>>> +};
>>>>>>> +
>> [...]
>>>>>>> -- 
>>>>>>> 1.9.1
>>>>>>
>>>>>> .
>>>>>>
>>>>
>>>> .
>>>>
> 
> .
> 

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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-14 13:42               ` Jian Hu
@ 2019-10-14 14:55                 ` Jerome Brunet
  2019-10-18  3:42                   ` Jian Hu
  0 siblings, 1 reply; 20+ messages in thread
From: Jerome Brunet @ 2019-10-14 14:55 UTC (permalink / raw)
  To: Jian Hu, Stephen Boyd
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Martin Blumenstingl,
	Michael Turquette, Qiufang Dai, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree


On Mon 14 Oct 2019 at 15:42, Jian Hu <jian.hu@amlogic.com> wrote:

>>> if peripheral clocks probe first, it will fail to get
>>> fixed_pll clocks. A lot of peripheral clocks parent are fclk_div2/3/5/7.
>>> and we can not get fclk_div2/3/5/7 clocks.
>>
>> What does "fail" mean ?
>> I intended to get clock using devm_clk_get API in each driver, In this 
> scene,it will get failed because of the clock not being reigstered. In
> fact, we could not use devm_clk_get.

Unless I missed somthing, I don't see why you would need to call
devm_clk_get(). This is now handled directly by the framework.

>>>
>>> I can think of two solutions:
>>> 1) Do not describe xtal_fixpll, xtal_hifipll.
>>>     that is to say, do not decribe the SYS_OSCIN_CTRL register.
>>>
>>> 2) Put peripheral and pll clock driver in one driver.
>>
>> Those are work arounds. Actually fixing the problem is usually
>> preferable.
>>
>>   So if rephrase your problem:
>>
>>   * We have 2 clock controllers (A and B)
>>   * Clock are passed between the controllers using DT
>>   * We have a PLL in controller B which is used by clocks in
>>     controller A.
>>   * the PLL parent clock is in controller A.
>>
> Yeah, it is the scene.
>> => So if I understand correctly you are saying that it will "fail"
>> because there is a circular dependency between controller A and B, right
>> ?
>>
>> Do you have evidence that your problem comes from this circular
>> dependency ?
>>
> I have realized the peripheral driver and PLL drivers,
>
> PLL driver probes first, Peripheral clock driver is the second.

It should work regarless of the order.

>
> In addition,for A1 SoC, it will not work using meson_clk_pll_ops,
>
> it needs strictly sequence,so maybe another ops is required.hifi pll will
> be sent with sys pll and CPU clock driver.

The PCie PLL has a good reason to have a single frequency, only one is needed

That's the case the case of the HIFI PLL which, as explained in previous
mails, needs to provide more that the single frenquency you have described.

If the pll driver needs to extended with new ops that's fine. Please
explain this "strict sequence" you are refering too.
What is part of the initial settings, what needs to be done each time ?

>> AFAIK, CCF will orphan the clock and continue if the parent is not
>> available. Later, when the parent comes up, the orphan will be
>> reparented.
>>
>> IOW, the problem you are reporting should already be covered by CCF.
>>
>>>
>>> And  which sulution is better above two?
>>
>> Neither, I'm afraid
>>
>>>
>>> Or maybe other good ideas for it?
>>
>> My bet would be that an important clocks (maybe more than 1) is being
>> gated during the init process.
>>
>> Maybe you should try the command line parameter "clk_ignore_unused"
>> until you get things running with your 2 controllers.
>>
>>>
>>> On 2019/9/29 17:38, Jian Hu wrote:
>>>>
>>>>
>>>> On 2019/9/27 21:32, Jerome Brunet wrote:
>>>>>
>>>>> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>
>>>>>> Hi, Jerome
>>>>>>
>>>>>> Thank you for review.
>>>>>>
>>>>>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>>>>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>>
>>>>>>>> The Amlogic A1 clock includes three parts:
>>>>>>>> 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>
>>>>>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>>>>>> ---
>>>>>>>>     arch/arm64/Kconfig.platforms |    1 +
>>>>>>>>     drivers/clk/meson/Kconfig    |   10 +
>>>>>>>>     drivers/clk/meson/Makefile   |    1 +
>>>>>>>>     drivers/clk/meson/a1.c       | 2617
>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>     drivers/clk/meson/a1.h       |  172 +++
>>>>>>>>     5 files changed, 2801 insertions(+)
>>>>>>>>     create mode 100644 drivers/clk/meson/a1.c
>>>>>>>>     create mode 100644 drivers/clk/meson/a1.h
>>>>>>>>
>>> [...]
>>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..26edae0f
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>>> @@ -0,0 +1,2617 @@
>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>> +#include <linux/init.h>
>>>>>>>> +#include <linux/of_device.h>
>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>> +#include <linux/of_address.h>
>>>>>>>> +#include "clk-mpll.h"
>>>>>>>> +#include "clk-pll.h"
>>>>>>>> +#include "clk-regmap.h"
>>>>>>>> +#include "vid-pll-div.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_ops,
>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>> +            .fw_name = "xtal",
>>>>>>>> +        },
>>>>>>>> +        .num_parents = 1,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>
>>>>>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>>>>>> Please review your other clocks with this in mind
>>>>>>>
>>>>>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>>>>>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +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,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +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,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>
>>>>>>> How is an USB clock critical to the system ?
>>>>>>> Please review your other clocks with comment in mind ...
>>>>>> the usb clock does not affect the system,
>>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>>
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +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,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>> the usb clock does not affect the system,
>>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>>> +
>>>>>>>> +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,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>> CLK_IS_CRITICAL is need to lock hifi pll.
>>>>>
>>>>> That's not how CCF works, this falg is not ok here.
>>>>> CCF will enable this clock before calling enable on your hifi pll
>>>>>
>>>> ok, I will remove it.
>>>>>>>> +
>>>>>>>> +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,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>> when CPU clock is at fixed clock, sys pll
>>>>>> will be disabled, xtal_syspll will be disabled too.
>>>>>> when setting sys pll, call clk_set_rate to lock
>>>>>> sys pll, add RO ops to avoid disabling the clock
>>>>>
>>>>> Again not Ok.
>>>>> If you mechanism to lock the PLL is properly implemented in the enable
>>>>> callback of the sys pll, still kind of work around are not needed
>>>>>
>>>>> This has worked on the pll we had so far.
>>>>>
>>>> ok, I will remove it.
>>>>>>
>>>>>>>> +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,
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>> CLK_IS_CRITICAL is need to lock dds
>>>>>>>> +
>>>>>>>> +/* fixed pll = 1536M
>>>>>>>> + *
>>>>>>>> + * fixed pll ----- fclk_div2 = 768M
>>>>>>>> + *           |
>>>>>>>> + *           ----- fclk_div3 = 512M
>>>>>>>> + *           |
>>>>>>>> + *           ----- fclk_div5 = 307.2M
>>>>>>>> + *           |
>>>>>>>> + *           ----- fclk_div7 = 219.4M
>>>>>>>> + */
>>>>>>>
>>>>>>> The framework will make those calculation ... you can remove this
>>>>>>>
>>>>>> ok, I will remote the comment.
>>>>>>>> +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_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_xtal_fixpll.hw
>>>>>>>> +        },
>>>>>>>> +        .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,
>>>>>>>> +        .flags = CLK_IGNORE_UNUSED,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>>>>>> +    PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +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 = 0x10022200 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4,    .def = 0x00301000 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us =
>>>>>>>> 10 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0,    .def = 0x15f11480, .delay_us
>>>>>>>> = 40 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001140 },
>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001100 },
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>>>>>> + * a strict register sequence to enable the PLL.
>>>>>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>>>>>> + */
>>>>>>>
>>>>>>> Could you elaborate on this ? What need to be done to enable the clock
>>>>>>> ?
>>>>>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>>>>>> might be desirable for audio use case. Why is this one restricted to
>>>>>>> one
>>>>>>> particular rate ?
>>>>>>>
>>>>>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>>>>>
>>>>>> 614.4M can meet the three frequency.
>>>>>>
>>>>>> after the hifi pll, there are two dividers in Audio clock.
>>>>>>
>>>>>> 614.4M/3200 = 192khz
>>>>>>
>>>>>> 614.4M/12800 = 48khz
>>>>>>
>>>>>> 614,4M/13932 = 44.0999khz
>>>>>
>>>>> It does not really answer my question though.
>>>>> You are locking a use case here, which is 32 bit sample width
>>>>>
>>>>> We have other constraint with the upstream audio driver, and we usually
>>>>> looking for base frequency that a multiple of 768 (24*32).
>>>>>
>>>>> If you need your PLL to be set to a particular rate for a use case, the
>>>>> correct way is "assigned-rate" in DT
>>>>>
>>>>> so the question still stands, the HIFI pll before was pretty easy to set
>>>>> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
>>>>> If yes, could you decribe the constraints.
>>>>>
>>>>> All this took us a long time to figure out on our own, which is why I'd
>>>>> prefer to get the proper constraints in from the beginning this time
>>>>>
>>>> ok, I will verify it and  describe the constraints about it
>>>>>
>>>>>>
>>>>>>>> +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,
>>>>>>>> +        },
>>>>>>>> +        .table = a1_hifi_pll_params_table,
>>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>>> +    },
>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>> +        .name = "hifi_pll",
>>>>>>>> +        .ops = &meson_clk_pcie_pll_ops,
>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>> +            &a1_xtal_hifipll.hw
>>>>>>>> +        },
>>>>>>>> +        .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,
>>>>>>>> +        /*
>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>> core
>>>>>>>> +         * or its children clocks.
>>>>>>>> +         */
>>>>>>>
>>>>>>> The meaning of this flag is already documented in clk-provider.h
>>>>>>> The reason why you need this flag is lot more interesting here ...
>>>>>>>
>>>>>>> Same below
>>>>>> ok, I will replace new comments here.
>>>>>>>
>>>>>>>> +        .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,
>>>>>>>> +        /*
>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>> core
>>>>>>>> +         * its children clocks.
>>>>>>>> +         */
>>>>>>>> +        .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,
>>>>>>>> +        /*
>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>> core
>>>>>>>> +         * its children clocks.
>>>>>>>> +         */
>>>>>>>> +        .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 = 23,
>>>>>>>> +    },
>>>>>>>> +    .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,
>>>>>>>> +        /*
>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>> core
>>>>>>>> +         * or its children clock.
>>>>>>>> +         */
>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>> +    },
>>>>>>>> +};
>>>>>>>> +
>>> [...]
>>>>>>>> -- 
>>>>>>>> 1.9.1
>>>>>>>
>>>>>>> .
>>>>>>>
>>>>>
>>>>> .
>>>>>
>>
>> .
>>


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

* Re: [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver
  2019-10-14 14:55                 ` Jerome Brunet
@ 2019-10-18  3:42                   ` Jian Hu
  0 siblings, 0 replies; 20+ messages in thread
From: Jian Hu @ 2019-10-18  3:42 UTC (permalink / raw)
  To: Jerome Brunet, Stephen Boyd
  Cc: Neil Armstrong, Jianxin Pan, Kevin Hilman, Martin Blumenstingl,
	Michael Turquette, Qiufang Dai, linux-clk, linux-amlogic,
	linux-arm-kernel, linux-kernel, devicetree

Hi, jerome

On 2019/10/14 22:55, Jerome Brunet wrote:
> 
> On Mon 14 Oct 2019 at 15:42, Jian Hu <jian.hu@amlogic.com> wrote:
> 
>>>> if peripheral clocks probe first, it will fail to get
>>>> fixed_pll clocks. A lot of peripheral clocks parent are fclk_div2/3/5/7.
>>>> and we can not get fclk_div2/3/5/7 clocks.
>>>
>>> What does "fail" mean ?
>>> I intended to get clock using devm_clk_get API in each driver, In this
>> scene,it will get failed because of the clock not being reigstered. In
>> fact, we could not use devm_clk_get.
> 
> Unless I missed somthing, I don't see why you would need to call
> devm_clk_get(). This is now handled directly by the framework.
> 
Just my wrong idea,I had not noticed the CCF would do it.
>>>>
>>>> I can think of two solutions:
>>>> 1) Do not describe xtal_fixpll, xtal_hifipll.
>>>>      that is to say, do not decribe the SYS_OSCIN_CTRL register.
>>>>
>>>> 2) Put peripheral and pll clock driver in one driver.
>>>
>>> Those are work arounds. Actually fixing the problem is usually
>>> preferable.
>>>
>>>    So if rephrase your problem:
>>>
>>>    * We have 2 clock controllers (A and B)
>>>    * Clock are passed between the controllers using DT
>>>    * We have a PLL in controller B which is used by clocks in
>>>      controller A.
>>>    * the PLL parent clock is in controller A.
>>>
>> Yeah, it is the scene.
>>> => So if I understand correctly you are saying that it will "fail"
>>> because there is a circular dependency between controller A and B, right
>>> ?
>>>
>>> Do you have evidence that your problem comes from this circular
>>> dependency ?
>>>
>> I have realized the peripheral driver and PLL drivers,
>>
>> PLL driver probes first, Peripheral clock driver is the second.
> 
> It should work regarless of the order.
> 
>>
>> In addition,for A1 SoC, it will not work using meson_clk_pll_ops,
>>
>> it needs strictly sequence,so maybe another ops is required.hifi pll will
>> be sent with sys pll and CPU clock driver.
> 
> The PCie PLL has a good reason to have a single frequency, only one is needed
> 
> That's the case the case of the HIFI PLL which, as explained in previous
> mails, needs to provide more that the single frenquency you have described.
> 
> If the pll driver needs to extended with new ops that's fine. Please
> explain this "strict sequence" you are refering too.
> What is part of the initial settings, what needs to be done each time ?
> 
The inital settings is the PLL internal analog modules Power-on 
sequence, and it is provided by the VLSI colleague.

For A1 PLL, the pll lock monitor block will initialise again in each 
time. It is the internal principle.It should keep the strict sequence 
when set one target frequency.

>>> AFAIK, CCF will orphan the clock and continue if the parent is not
>>> available. Later, when the parent comes up, the orphan will be
>>> reparented.
>>>
>>> IOW, the problem you are reporting should already be covered by CCF.
>>>
>>>>
>>>> And  which sulution is better above two?
>>>
>>> Neither, I'm afraid
>>>
>>>>
>>>> Or maybe other good ideas for it?
>>>
>>> My bet would be that an important clocks (maybe more than 1) is being
>>> gated during the init process.
>>>
>>> Maybe you should try the command line parameter "clk_ignore_unused"
>>> until you get things running with your 2 controllers.
>>>
>>>>
>>>> On 2019/9/29 17:38, Jian Hu wrote:
>>>>>
>>>>>
>>>>> On 2019/9/27 21:32, Jerome Brunet wrote:
>>>>>>
>>>>>> On Fri 27 Sep 2019 at 11:52, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>
>>>>>>> Hi, Jerome
>>>>>>>
>>>>>>> Thank you for review.
>>>>>>>
>>>>>>> On 2019/9/25 23:09, Jerome Brunet wrote:
>>>>>>>> On Wed 25 Sep 2019 at 19:44, Jian Hu <jian.hu@amlogic.com> wrote:
>>>>>>>>
>>>>>>>>> The Amlogic A1 clock includes three parts:
>>>>>>>>> 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>
>>>>>>>>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>>>>>>>>> ---
>>>>>>>>>      arch/arm64/Kconfig.platforms |    1 +
>>>>>>>>>      drivers/clk/meson/Kconfig    |   10 +
>>>>>>>>>      drivers/clk/meson/Makefile   |    1 +
>>>>>>>>>      drivers/clk/meson/a1.c       | 2617
>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>>      drivers/clk/meson/a1.h       |  172 +++
>>>>>>>>>      5 files changed, 2801 insertions(+)
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1.c
>>>>>>>>>      create mode 100644 drivers/clk/meson/a1.h
>>>>>>>>>
>>>> [...]
>>>>>>>>> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..26edae0f
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/clk/meson/a1.c
>>>>>>>>> @@ -0,0 +1,2617 @@
>>>>>>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#include <linux/clk-provider.h>
>>>>>>>>> +#include <linux/init.h>
>>>>>>>>> +#include <linux/of_device.h>
>>>>>>>>> +#include <linux/platform_device.h>
>>>>>>>>> +#include <linux/of_address.h>
>>>>>>>>> +#include "clk-mpll.h"
>>>>>>>>> +#include "clk-pll.h"
>>>>>>>>> +#include "clk-regmap.h"
>>>>>>>>> +#include "vid-pll-div.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_ops,
>>>>>>>>> +        .parent_data = &(const struct clk_parent_data) {
>>>>>>>>> +            .fw_name = "xtal",
>>>>>>>>> +        },
>>>>>>>>> +        .num_parents = 1,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>
>>>>>>>> Is CCF even expected to touch this ever ? what about RO ops ?
>>>>>>>> Please review your other clocks with this in mind
>>>>>>>>
>>>>>>> the clock should not be changed at runtime.clk_regmap_gate_ro_ops
>>>>>>> is a good idea. Set RO ops and remove the CLK_IS_CRITICAL flag.
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +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,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +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,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>
>>>>>>>> How is an USB clock critical to the system ?
>>>>>>>> Please review your other clocks with comment in mind ...
>>>>>>> the usb clock does not affect the system,
>>>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>>>
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +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,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>> the usb clock does not affect the system,
>>>>>>> remove the CLK_IS_CRITICAL flag
>>>>>>>>> +
>>>>>>>>> +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,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>> CLK_IS_CRITICAL is need to lock hifi pll.
>>>>>>
>>>>>> That's not how CCF works, this falg is not ok here.
>>>>>> CCF will enable this clock before calling enable on your hifi pll
>>>>>>
>>>>> ok, I will remove it.
>>>>>>>>> +
>>>>>>>>> +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,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>> when CPU clock is at fixed clock, sys pll
>>>>>>> will be disabled, xtal_syspll will be disabled too.
>>>>>>> when setting sys pll, call clk_set_rate to lock
>>>>>>> sys pll, add RO ops to avoid disabling the clock
>>>>>>
>>>>>> Again not Ok.
>>>>>> If you mechanism to lock the PLL is properly implemented in the enable
>>>>>> callback of the sys pll, still kind of work around are not needed
>>>>>>
>>>>>> This has worked on the pll we had so far.
>>>>>>
>>>>> ok, I will remove it.
>>>>>>>
>>>>>>>>> +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,
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>> CLK_IS_CRITICAL is need to lock dds
>>>>>>>>> +
>>>>>>>>> +/* fixed pll = 1536M
>>>>>>>>> + *
>>>>>>>>> + * fixed pll ----- fclk_div2 = 768M
>>>>>>>>> + *           |
>>>>>>>>> + *           ----- fclk_div3 = 512M
>>>>>>>>> + *           |
>>>>>>>>> + *           ----- fclk_div5 = 307.2M
>>>>>>>>> + *           |
>>>>>>>>> + *           ----- fclk_div7 = 219.4M
>>>>>>>>> + */
>>>>>>>>
>>>>>>>> The framework will make those calculation ... you can remove this
>>>>>>>>
>>>>>>> ok, I will remote the comment.
>>>>>>>>> +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_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_xtal_fixpll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .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,
>>>>>>>>> +        .flags = CLK_IGNORE_UNUSED,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +static const struct pll_params_table a1_hifi_pll_params_table[] = {
>>>>>>>>> +    PLL_PARAMS(128, 5), /* DCO = 614.4M */
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +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 = 0x10022200 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL4,    .def = 0x00301000 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f19480 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f19480, .delay_us =
>>>>>>>>> 10 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL0,    .def = 0x15f11480, .delay_us
>>>>>>>>> = 40 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001140 },
>>>>>>>>> +    { .reg = ANACTRL_HIFIPLL_CTRL2,    .def = 0x00001100 },
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * The Meson A1 HIFI PLL is 614.4M, it requires
>>>>>>>>> + * a strict register sequence to enable the PLL.
>>>>>>>>> + * set meson_clk_pcie_pll_ops as its ops
>>>>>>>>> + */
>>>>>>>>
>>>>>>>> Could you elaborate on this ? What need to be done to enable the clock
>>>>>>>> ?
>>>>>>>> Also the HIFI PLL used to be able to do a *LOT* of different rate which
>>>>>>>> might be desirable for audio use case. Why is this one restricted to
>>>>>>>> one
>>>>>>>> particular rate ?
>>>>>>>>
>>>>>>> The audio working frequency are 44.1khz, 48khz and 192khz.
>>>>>>>
>>>>>>> 614.4M can meet the three frequency.
>>>>>>>
>>>>>>> after the hifi pll, there are two dividers in Audio clock.
>>>>>>>
>>>>>>> 614.4M/3200 = 192khz
>>>>>>>
>>>>>>> 614.4M/12800 = 48khz
>>>>>>>
>>>>>>> 614,4M/13932 = 44.0999khz
>>>>>>
>>>>>> It does not really answer my question though.
>>>>>> You are locking a use case here, which is 32 bit sample width
>>>>>>
>>>>>> We have other constraint with the upstream audio driver, and we usually
>>>>>> looking for base frequency that a multiple of 768 (24*32).
>>>>>>
>>>>>> If you need your PLL to be set to a particular rate for a use case, the
>>>>>> correct way is "assigned-rate" in DT
>>>>>>
>>>>>> so the question still stands, the HIFI pll before was pretty easy to set
>>>>>> at a wide variety of rate (same as GP0) ... is it not the case anymore ?
>>>>>> If yes, could you decribe the constraints.
>>>>>>
>>>>>> All this took us a long time to figure out on our own, which is why I'd
>>>>>> prefer to get the proper constraints in from the beginning this time
>>>>>>
>>>>> ok, I will verify it and  describe the constraints about it
>>>>>>
>>>>>>>
>>>>>>>>> +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,
>>>>>>>>> +        },
>>>>>>>>> +        .table = a1_hifi_pll_params_table,
>>>>>>>>> +        .init_regs = a1_hifi_init_regs,
>>>>>>>>> +        .init_count = ARRAY_SIZE(a1_hifi_init_regs),
>>>>>>>>> +    },
>>>>>>>>> +    .hw.init = &(struct clk_init_data){
>>>>>>>>> +        .name = "hifi_pll",
>>>>>>>>> +        .ops = &meson_clk_pcie_pll_ops,
>>>>>>>>> +        .parent_hws = (const struct clk_hw *[]) {
>>>>>>>>> +            &a1_xtal_hifipll.hw
>>>>>>>>> +        },
>>>>>>>>> +        .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,
>>>>>>>>> +        /*
>>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>>> core
>>>>>>>>> +         * or its children clocks.
>>>>>>>>> +         */
>>>>>>>>
>>>>>>>> The meaning of this flag is already documented in clk-provider.h
>>>>>>>> The reason why you need this flag is lot more interesting here ...
>>>>>>>>
>>>>>>>> Same below
>>>>>>> ok, I will replace new comments here.
>>>>>>>>
>>>>>>>>> +        .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,
>>>>>>>>> +        /*
>>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>>> core
>>>>>>>>> +         * its children clocks.
>>>>>>>>> +         */
>>>>>>>>> +        .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,
>>>>>>>>> +        /*
>>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>>> core
>>>>>>>>> +         * its children clocks.
>>>>>>>>> +         */
>>>>>>>>> +        .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 = 23,
>>>>>>>>> +    },
>>>>>>>>> +    .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,
>>>>>>>>> +        /*
>>>>>>>>> +         * add CLK_IS_CRITICAL flag to avoid being disabled by clk
>>>>>>>>> core
>>>>>>>>> +         * or its children clock.
>>>>>>>>> +         */
>>>>>>>>> +        .flags = CLK_IS_CRITICAL,
>>>>>>>>> +    },
>>>>>>>>> +};
>>>>>>>>> +
>>>> [...]
>>>>>>>>> -- 
>>>>>>>>> 1.9.1
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>
>>>>>> .
>>>>>>
>>>
>>> .
>>>
> 
> .
> 

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

* Re: [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings
  2019-09-27 20:10   ` Rob Herring
@ 2019-12-18  7:30     ` Jian Hu
  0 siblings, 0 replies; 20+ messages in thread
From: Jian Hu @ 2019-12-18  7:30 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jerome Brunet, Neil Armstrong, Jianxin Pan, devicetree,
	Martin Blumenstingl, Kevin Hilman, Michael Turquette,
	linux-kernel, Stephen Boyd, Qiufang Dai, linux-amlogic,
	linux-clk,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi Rob

Thanks for your review

On 2019/9/28 4:10, Rob Herring wrote:
> On Wed, Sep 25, 2019 at 6:45 AM 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>
>> Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
>> ---
>>   .../devicetree/bindings/clock/amlogic,a1-clkc.yaml |  65 +++++++++++++
>>   include/dt-bindings/clock/a1-clkc.h                | 102 +++++++++++++++++++++
>>   2 files changed, 167 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>>   create mode 100644 include/dt-bindings/clock/a1-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..f012eb2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
>> @@ -0,0 +1,65 @@
>> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> 
> (GPL-2.0-only OR BSD-2-Clause) please.
> 
Sorry, I missed your reply. I will change it in next version v5.
> Rob
> 
> .
> 

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

end of thread, other threads:[~2019-12-18  7:31 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-25 11:44 [PATCH 0/2] add Amlogic A1 clock controller driver Jian Hu
2019-09-25 11:44 ` [PATCH 1/2] dt-bindings: clock: meson: add A1 clock controller bindings Jian Hu
2019-09-25 14:29   ` Jerome Brunet
2019-09-27  6:08     ` Jian Hu
2019-09-27 20:10   ` Rob Herring
2019-12-18  7:30     ` Jian Hu
2019-09-25 11:44 ` [PATCH 2/2] clk: meson: a1: add support for Amlogic A1 clock driver Jian Hu
2019-09-25 13:12   ` Stephen Boyd
2019-09-27  3:11     ` Jian Hu
2019-09-27 12:56       ` Jerome Brunet
2019-09-29  6:15         ` Jian Hu
2019-09-25 15:09   ` Jerome Brunet
2019-09-27  9:52     ` Jian Hu
2019-09-27 13:32       ` Jerome Brunet
2019-09-29  9:38         ` Jian Hu
2019-10-08  8:03           ` Jian Hu
2019-10-11  7:39             ` Jerome Brunet
2019-10-14 13:42               ` Jian Hu
2019-10-14 14:55                 ` Jerome Brunet
2019-10-18  3:42                   ` 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).