* [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock
@ 2024-09-14 5:25 Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller Xianwei Zhao via B4 Relay
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
The patchset adds support for the peripheral and PLL clock controller
found on the Amlogic A5 SoC family, such as A113X2.
Some clocks are provided by security zones. These clock accessed
througth SCMI driver in linux, inlcuding OSC, SYS_CLK, AXI_CLK,
CPU_CLK, DSU_CLK, GP1_PLL, FIXED_PLL_DCO, FIXED_PLL, SYS_PLL_DIV16,
ACLKM, CPU_CLK_DIV16, FCLK_50M_PREDIV, FCLK_50M_DIV, FCLK_50M,
FCLK_DIV2_DIV, FCLK_DIV2, FCLK_DIV2P5_DIV, FCLK_DIV2P5, FCLK_DIV3_DIV,
FCLK_DIV3, FCLK_DIV4_DIV, FCLK_DIV4, FCLK_DIV5_DIV, FCLK_DIV5,
FCLK_DIV7_DIV and FCLK_DIV7.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
Chuan Liu (5):
dt-bindings: clock: add Amlogic A5 PLL clock controller
dt-bindings: clock: add Amlogic A5 SCMI clock controller support
dt-bindings: clock: add Amlogic A5 peripherals clock controller
clk: meson: add support for the A5 SoC PLL clock
clk: meson: add A5 clock peripherals controller driver
.../clock/amlogic,a5-peripherals-clkc.yaml | 126 ++
.../bindings/clock/amlogic,a5-pll-clkc.yaml | 62 +
drivers/clk/meson/Kconfig | 28 +
drivers/clk/meson/Makefile | 2 +
drivers/clk/meson/a5-peripherals.c | 1471 ++++++++++++++++++++
drivers/clk/meson/a5-pll.c | 553 ++++++++
.../clock/amlogic,a5-peripherals-clkc.h | 139 ++
include/dt-bindings/clock/amlogic,a5-pll-clkc.h | 24 +
include/dt-bindings/clock/amlogic,a5-scmi-clkc.h | 37 +
9 files changed, 2442 insertions(+)
---
base-commit: c92651b5d51738859098d59692ff8ff4fa85bcd6
change-id: 20240911-a5-clk-35c49acb34e1
Best regards,
--
Xianwei Zhao <xianwei.zhao@amlogic.com>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
@ 2024-09-14 5:25 ` Xianwei Zhao via B4 Relay
2024-09-18 16:06 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support Xianwei Zhao via B4 Relay
` (3 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
From: Chuan Liu <chuan.liu@amlogic.com>
Add the PLL clock controller dt-bindings for Amlogic A5 SoC family.
Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
.../bindings/clock/amlogic,a5-pll-clkc.yaml | 62 ++++++++++++++++++++++
include/dt-bindings/clock/amlogic,a5-pll-clkc.h | 24 +++++++++
2 files changed, 86 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,a5-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a5-pll-clkc.yaml
new file mode 100644
index 000000000000..ef9e40193a1c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a5-pll-clkc.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a5-pll-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A5 series PLL Clock Controller
+
+maintainers:
+ - Chuan Liu <chuan.liu@amlogic.com>
+ - Xianwei Zhao <xianwei.zhao@amlogic.com>
+
+properties:
+ compatible:
+ const: amlogic,a5-pll-clkc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: input oscillator (usually at 24MHz)
+ - description: input fix pll dco
+ - description: input fix pll
+
+ clock-names:
+ items:
+ - const: xtal_24m
+ - const: fix_dco
+ - const: fix
+
+ "#clock-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ apb {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@8000 {
+ compatible = "amlogic,a5-pll-clkc";
+ reg = <0x0 0x8000 0x0 0x1a4>;
+ clocks = <&xtal_24m>,
+ <&scmi_clk 6>,
+ <&scmi_clk 7>;
+ clock-names = "xtal_24m",
+ "fix_dco",
+ "fix";
+ #clock-cells = <1>;
+ };
+ };
diff --git a/include/dt-bindings/clock/amlogic,a5-pll-clkc.h b/include/dt-bindings/clock/amlogic,a5-pll-clkc.h
new file mode 100644
index 000000000000..a74c448a8d8a
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a5-pll-clkc.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
+ * Author: Chuan Liu <chuan.liu@amlogic.com>
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_AMLOGIC_A5_PLL_CLKC_H
+#define _DT_BINDINGS_CLOCK_AMLOGIC_A5_PLL_CLKC_H
+
+#define CLKID_MPLL_PREDIV 0
+#define CLKID_MPLL0_DIV 1
+#define CLKID_MPLL0 2
+#define CLKID_MPLL1_DIV 3
+#define CLKID_MPLL1 4
+#define CLKID_MPLL2_DIV 5
+#define CLKID_MPLL2 6
+#define CLKID_MPLL3_DIV 7
+#define CLKID_MPLL3 8
+#define CLKID_GP0_PLL_DCO 9
+#define CLKID_GP0_PLL 10
+#define CLKID_HIFI_PLL_DCO 11
+#define CLKID_HIFI_PLL 12
+
+#endif /* _DT_BINDINGS_CLOCK_AMLOGIC_A5_PLL_CLKC_H */
--
2.37.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller Xianwei Zhao via B4 Relay
@ 2024-09-14 5:25 ` Xianwei Zhao via B4 Relay
2024-09-18 16:07 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller Xianwei Zhao via B4 Relay
` (2 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
From: Chuan Liu <chuan.liu@amlogic.com>
Add the SCMI clock controller dt-bindings for Amlogic A5 SoC family.
Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
include/dt-bindings/clock/amlogic,a5-scmi-clkc.h | 37 ++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
new file mode 100644
index 000000000000..d35d1ff6bab3
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a5-scmi-clkc.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
+ * Author: Chuan Liu <chuan.liu@amlogic.com>
+ */
+
+#ifndef __AMLOGIC_A5_SCMI_CLKC_H
+#define __AMLOGIC_A5_SCMI_CLKC_H
+
+#define CLKID_OSC 0
+#define CLKID_SYS_CLK 1
+#define CLKID_AXI_CLK 2
+#define CLKID_CPU_CLK 3
+#define CLKID_DSU_CLK 4
+#define CLKID_GP1_PLL 5
+#define CLKID_FIXED_PLL_DCO 6
+#define CLKID_FIXED_PLL 7
+#define CLKID_ACLKM 8
+#define CLKID_SYS_PLL_DIV16 9
+#define CLKID_CPU_CLK_DIV16 10
+#define CLKID_FCLK_50M_PREDIV 11
+#define CLKID_FCLK_50M_DIV 12
+#define CLKID_FCLK_50M 13
+#define CLKID_FCLK_DIV2_DIV 14
+#define CLKID_FCLK_DIV2 15
+#define CLKID_FCLK_DIV2P5_DIV 16
+#define CLKID_FCLK_DIV2P5 17
+#define CLKID_FCLK_DIV3_DIV 18
+#define CLKID_FCLK_DIV3 19
+#define CLKID_FCLK_DIV4_DIV 20
+#define CLKID_FCLK_DIV4 21
+#define CLKID_FCLK_DIV5_DIV 22
+#define CLKID_FCLK_DIV5 23
+#define CLKID_FCLK_DIV7_DIV 24
+#define CLKID_FCLK_DIV7 25
+
+#endif /* __AMLOGIC_A5_SCMI_CLKC_H */
--
2.37.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support Xianwei Zhao via B4 Relay
@ 2024-09-14 5:25 ` Xianwei Zhao via B4 Relay
2024-09-18 16:13 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver Xianwei Zhao via B4 Relay
4 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
From: Chuan Liu <chuan.liu@amlogic.com>
Add the peripherals clock controller dt-bindings for Amlogic A5 SoC family.
Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
.../clock/amlogic,a5-peripherals-clkc.yaml | 126 +++++++++++++++++++
.../clock/amlogic,a5-peripherals-clkc.h | 139 +++++++++++++++++++++
2 files changed, 265 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,a5-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a5-peripherals-clkc.yaml
new file mode 100644
index 000000000000..6529b7c79768
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a5-peripherals-clkc.yaml
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a5-peripherals-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A5 series Peripheral Clock Controller
+
+maintainers:
+ - Xianwei Zhao <xianwei.zhao@amlogic.com>
+ - Chuan Liu <chuan.liu@amlogic.com>
+
+properties:
+ compatible:
+ const: amlogic,a5-peripherals-clkc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ minItems: 18
+ items:
+ - description: input oscillator (usually at 24MHz)
+ - description: input oscillators multiplexer
+ - description: input fix pll
+ - description: input fclk div 2
+ - description: input fclk div 2p5
+ - description: input fclk div 3
+ - description: input fclk div 4
+ - description: input fclk div 5
+ - description: input fclk div 7
+ - description: input mpll2
+ - description: input mpll3
+ - description: input gp0 pll
+ - description: input gp1 pll
+ - description: input hifi pll
+ - description: input sys clk
+ - description: input axi clk
+ - description: input sys pll div 16
+ - description: input cpu clk div 16
+ - description: input pad clock for rtc clk (optional)
+
+ clock-names:
+ minItems: 18
+ items:
+ - const: xtal_24m
+ - const: oscin
+ - const: fix
+ - const: fdiv2
+ - const: fdiv2p5
+ - const: fdiv3
+ - const: fdiv4
+ - const: fdiv5
+ - const: fdiv7
+ - const: mpll2
+ - const: mpll3
+ - const: gp0
+ - const: gp1
+ - const: hifi
+ - const: sysclk
+ - const: axiclk
+ - const: sysplldiv16
+ - const: cpudiv16
+ - const: pad_osc
+
+ "#clock-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ apb {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@0 {
+ compatible = "amlogic,a5-peripherals-clkc";
+ reg = <0x0 0x0 0x0 0x224>;
+ #clock-cells = <1>;
+ clocks = <&xtal_24m>,
+ <&scmi_clk 0>,
+ <&scmi_clk 7>,
+ <&scmi_clk 15>,
+ <&scmi_clk 17>,
+ <&scmi_clk 19>,
+ <&scmi_clk 21>,
+ <&scmi_clk 23>,
+ <&scmi_clk 25>,
+ <&clkc_pll 6>,
+ <&clkc_pll 8>,
+ <&clkc_pll 10>,
+ <&scmi_clk 5>,
+ <&clkc_pll 12>,
+ <&scmi_clk 1>,
+ <&scmi_clk 2>,
+ <&scmi_clk 9>,
+ <&scmi_clk 10>;
+ clock-names = "xtal_24m",
+ "oscin",
+ "fix",
+ "fdiv2",
+ "fdiv2p5",
+ "fdiv3",
+ "fdiv4",
+ "fdiv5",
+ "fdiv7",
+ "mpll2",
+ "mpll3",
+ "gp0",
+ "gp1",
+ "hifi",
+ "sysclk",
+ "axiclk",
+ "sysplldiv16",
+ "cpudiv16";
+ };
+ };
diff --git a/include/dt-bindings/clock/amlogic,a5-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,a5-peripherals-clkc.h
new file mode 100644
index 000000000000..0ba61520e2c1
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a5-peripherals-clkc.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
+/*
+ * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
+ * Author: Chuan Liu <chuan.liu@amlogic.com>
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_AMLOGIC_A5_PERIPHERALS_CLKC_H
+#define _DT_BINDINGS_CLOCK_AMLOGIC_A5_PERIPHERALS_CLKC_H
+
+#define CLKID_RTC_XTAL_CLKIN 0
+#define CLKID_RTC_32K_DIV 1
+#define CLKID_RTC_32K_MUX 2
+#define CLKID_RTC_32K 3
+#define CLKID_RTC_CLK 4
+#define CLKID_SYS_RESET_CTRL 5
+#define CLKID_SYS_PWR_CTRL 6
+#define CLKID_SYS_PAD_CTRL 7
+#define CLKID_SYS_CTRL 8
+#define CLKID_SYS_TS_PLL 9
+#define CLKID_SYS_DEV_ARB 10
+#define CLKID_SYS_MMC_PCLK 11
+#define CLKID_SYS_MAILBOX 12
+#define CLKID_SYS_CPU_CTRL 13
+#define CLKID_SYS_JTAG_CTRL 14
+#define CLKID_SYS_IR_CTRL 15
+#define CLKID_SYS_IRQ_CTRL 16
+#define CLKID_SYS_MSR_CLK 17
+#define CLKID_SYS_ROM 18
+#define CLKID_SYS_CPU_ARB 19
+#define CLKID_SYS_RSA 20
+#define CLKID_SYS_SAR_ADC 21
+#define CLKID_SYS_STARTUP 22
+#define CLKID_SYS_SECURE 23
+#define CLKID_SYS_SPIFC 24
+#define CLKID_SYS_DSPA 25
+#define CLKID_SYS_NNA 26
+#define CLKID_SYS_ETH_MAC 27
+#define CLKID_SYS_GIC 28
+#define CLKID_SYS_RAMA 29
+#define CLKID_SYS_BIG_NIC 30
+#define CLKID_SYS_RAMB 31
+#define CLKID_SYS_AUDIO_TOP 32
+#define CLKID_SYS_AUDIO_VAD 33
+#define CLKID_SYS_USB 34
+#define CLKID_SYS_SD_EMMC_A 35
+#define CLKID_SYS_SD_EMMC_C 36
+#define CLKID_SYS_PWM_AB 37
+#define CLKID_SYS_PWM_CD 38
+#define CLKID_SYS_PWM_EF 39
+#define CLKID_SYS_PWM_GH 40
+#define CLKID_SYS_SPICC_1 41
+#define CLKID_SYS_SPICC_0 42
+#define CLKID_SYS_UART_A 43
+#define CLKID_SYS_UART_B 44
+#define CLKID_SYS_UART_C 45
+#define CLKID_SYS_UART_D 46
+#define CLKID_SYS_UART_E 47
+#define CLKID_SYS_I2C_M_A 48
+#define CLKID_SYS_I2C_M_B 49
+#define CLKID_SYS_I2C_M_C 50
+#define CLKID_SYS_I2C_M_D 51
+#define CLKID_SYS_RTC 52
+#define CLKID_AXI_AUDIO_VAD 53
+#define CLKID_AXI_AUDIO_TOP 54
+#define CLKID_AXI_SYS_NIC 55
+#define CLKID_AXI_RAMB 56
+#define CLKID_AXI_RAMA 57
+#define CLKID_AXI_CPU_DMC 58
+#define CLKID_AXI_NNA 59
+#define CLKID_AXI_DEV1_DMC 60
+#define CLKID_AXI_DEV0_DMC 61
+#define CLKID_AXI_DSP_DMC 62
+#define CLKID_12_24M_IN 63
+#define CLKID_12M_24M 64
+#define CLKID_FCLK_25M_DIV 65
+#define CLKID_FCLK_25M 66
+#define CLKID_GEN_SEL 67
+#define CLKID_GEN_DIV 68
+#define CLKID_GEN 69
+#define CLKID_SARADC_SEL 70
+#define CLKID_SARADC_DIV 71
+#define CLKID_SARADC 72
+#define CLKID_PWM_A_SEL 73
+#define CLKID_PWM_A_DIV 74
+#define CLKID_PWM_A 75
+#define CLKID_PWM_B_SEL 76
+#define CLKID_PWM_B_DIV 77
+#define CLKID_PWM_B 78
+#define CLKID_PWM_C_SEL 79
+#define CLKID_PWM_C_DIV 80
+#define CLKID_PWM_C 81
+#define CLKID_PWM_D_SEL 82
+#define CLKID_PWM_D_DIV 83
+#define CLKID_PWM_D 84
+#define CLKID_PWM_E_SEL 85
+#define CLKID_PWM_E_DIV 86
+#define CLKID_PWM_E 87
+#define CLKID_PWM_F_SEL 88
+#define CLKID_PWM_F_DIV 89
+#define CLKID_PWM_F 90
+#define CLKID_PWM_G_SEL 91
+#define CLKID_PWM_G_DIV 92
+#define CLKID_PWM_G 93
+#define CLKID_PWM_H_SEL 94
+#define CLKID_PWM_H_DIV 95
+#define CLKID_PWM_H 96
+#define CLKID_SPICC_0_SEL 97
+#define CLKID_SPICC_0_DIV 98
+#define CLKID_SPICC_0 99
+#define CLKID_SPICC_1_SEL 100
+#define CLKID_SPICC_1_DIV 101
+#define CLKID_SPICC_1 102
+#define CLKID_SD_EMMC_A_SEL 103
+#define CLKID_SD_EMMC_A_DIV 104
+#define CLKID_SD_EMMC_A 105
+#define CLKID_SD_EMMC_C_SEL 106
+#define CLKID_SD_EMMC_C_DIV 107
+#define CLKID_SD_EMMC_C 108
+#define CLKID_TS_DIV 109
+#define CLKID_TS 110
+#define CLKID_ETH_125M_DIV 111
+#define CLKID_ETH_125M 112
+#define CLKID_ETH_RMII_DIV 113
+#define CLKID_ETH_RMII 114
+#define CLKID_DSPA_0_SEL 115
+#define CLKID_DSPA_0_DIV 116
+#define CLKID_DSPA_0 117
+#define CLKID_DSPA_1_SEL 118
+#define CLKID_DSPA_1_DIV 119
+#define CLKID_DSPA_1 120
+#define CLKID_DSPA 121
+#define CLKID_NNA_CORE_SEL 122
+#define CLKID_NNA_CORE_DIV 123
+#define CLKID_NNA_CORE 124
+#define CLKID_NNA_AXI_SEL 125
+#define CLKID_NNA_AXI_DIV 126
+#define CLKID_NNA_AXI 127
+
+#endif /* _DT_BINDINGS_CLOCK_AMLOGIC_A5_PERIPHERALS_CLKC_H */
--
2.37.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
` (2 preceding siblings ...)
2024-09-14 5:25 ` [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller Xianwei Zhao via B4 Relay
@ 2024-09-14 5:25 ` Xianwei Zhao via B4 Relay
2024-09-24 14:45 ` Jerome Brunet
2024-09-14 5:25 ` [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver Xianwei Zhao via B4 Relay
4 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
From: Chuan Liu <chuan.liu@amlogic.com>
Add the PLL clock controller driver for the Amlogic A5 SoC family.
Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
drivers/clk/meson/Kconfig | 14 ++
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a5-pll.c | 553 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 568 insertions(+)
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 78f648c9c97d..2a713276e46c 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -132,6 +132,20 @@ config COMMON_CLK_A1_PERIPHERALS
device, A1 SoC Family. Say Y if you want A1 Peripherals clock
controller to work.
+config COMMON_CLK_A5_PLL
+ tristate "Amlogic A5 PLL clock controller"
+ depends on ARM64
+ default y
+ imply ARM_SCMI_PROTOCOL
+ imply COMMON_CLK_SCMI
+ select COMMON_CLK_MESON_REGMAP
+ select COMMON_CLK_MESON_PLL
+ select COMMON_CLK_MESON_CLKC_UTILS
+ help
+ Support for the PLL clock controller on Amlogic AV40x device, AKA A5.
+ Say Y if you want the board to work, because PLLs are the parent
+ of most peripherals.
+
config COMMON_CLK_C3_PLL
tristate "Amlogic C3 PLL clock controller"
depends on ARM64
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index bc56a47931c1..fc4b8a723145 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
+obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
diff --git a/drivers/clk/meson/a5-pll.c b/drivers/clk/meson/a5-pll.c
new file mode 100644
index 000000000000..d96ed72ef8d4
--- /dev/null
+++ b/drivers/clk/meson/a5-pll.c
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Amlogic A5 PLL Controller Driver
+ *
+ * Copyright (c) 2024 Amlogic, inc.
+ * Author: Chuan Liu <chuan.liu@amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,a5-pll-clkc.h>
+
+#define ANACTRL_FIXPLL_CTRL1 0x44
+#define ANACTRL_GP0PLL_CTRL0 0x80
+#define ANACTRL_GP0PLL_CTRL1 0x84
+#define ANACTRL_GP0PLL_CTRL2 0x88
+#define ANACTRL_GP0PLL_CTRL3 0x8c
+#define ANACTRL_GP0PLL_CTRL4 0x90
+#define ANACTRL_GP0PLL_CTRL5 0x94
+#define ANACTRL_GP0PLL_CTRL6 0x98
+#define ANACTRL_HIFIPLL_CTRL0 0x100
+#define ANACTRL_HIFIPLL_CTRL1 0x104
+#define ANACTRL_HIFIPLL_CTRL2 0x108
+#define ANACTRL_HIFIPLL_CTRL3 0x10c
+#define ANACTRL_HIFIPLL_CTRL4 0x110
+#define ANACTRL_HIFIPLL_CTRL5 0x114
+#define ANACTRL_HIFIPLL_CTRL6 0x118
+#define ANACTRL_MPLL_CTRL0 0x180
+#define ANACTRL_MPLL_CTRL1 0x184
+#define ANACTRL_MPLL_CTRL2 0x188
+#define ANACTRL_MPLL_CTRL3 0x18c
+#define ANACTRL_MPLL_CTRL4 0x190
+#define ANACTRL_MPLL_CTRL5 0x194
+#define ANACTRL_MPLL_CTRL6 0x198
+#define ANACTRL_MPLL_CTRL7 0x19c
+#define ANACTRL_MPLL_CTRL8 0x1a0
+
+static DEFINE_SPINLOCK(aml_clk_lock);
+
+static struct clk_fixed_factor mpll_prediv = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll_prediv",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fix_dco"
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct reg_sequence mpll0_init_regs[] = {
+ { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 },
+};
+
+static struct clk_regmap mpll0_div = {
+ .data = &(struct meson_clk_mpll_data){
+ .sdm = {
+ .reg_off = ANACTRL_MPLL_CTRL1,
+ .shift = 0,
+ .width = 14,
+ },
+ .sdm_en = {
+ .reg_off = ANACTRL_MPLL_CTRL1,
+ .shift = 30,
+ .width = 1,
+ },
+ .n2 = {
+ .reg_off = ANACTRL_MPLL_CTRL1,
+ .shift = 20,
+ .width = 9,
+ },
+ .ssen = {
+ .reg_off = ANACTRL_MPLL_CTRL1,
+ .shift = 29,
+ .width = 1,
+ },
+ .lock = &aml_clk_lock,
+ .init_regs = mpll0_init_regs,
+ .init_count = ARRAY_SIZE(mpll0_init_regs),
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll0_div",
+ .ops = &meson_clk_mpll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &mpll_prediv.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap mpll0 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_MPLL_CTRL1,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll0",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &mpll0_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct reg_sequence mpll1_init_regs[] = {
+ { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 },
+};
+
+static struct clk_regmap mpll1_div = {
+ .data = &(struct meson_clk_mpll_data){
+ .sdm = {
+ .reg_off = ANACTRL_MPLL_CTRL3,
+ .shift = 0,
+ .width = 14,
+ },
+ .sdm_en = {
+ .reg_off = ANACTRL_MPLL_CTRL3,
+ .shift = 30,
+ .width = 1,
+ },
+ .n2 = {
+ .reg_off = ANACTRL_MPLL_CTRL3,
+ .shift = 20,
+ .width = 9,
+ },
+ .ssen = {
+ .reg_off = ANACTRL_MPLL_CTRL3,
+ .shift = 29,
+ .width = 1,
+ },
+ .lock = &aml_clk_lock,
+ .init_regs = mpll1_init_regs,
+ .init_count = ARRAY_SIZE(mpll1_init_regs),
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll1_div",
+ .ops = &meson_clk_mpll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &mpll_prediv.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap mpll1 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_MPLL_CTRL3,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll1",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &mpll1_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct reg_sequence mpll2_init_regs[] = {
+ { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 },
+};
+
+static struct clk_regmap mpll2_div = {
+ .data = &(struct meson_clk_mpll_data){
+ .sdm = {
+ .reg_off = ANACTRL_MPLL_CTRL5,
+ .shift = 0,
+ .width = 14,
+ },
+ .sdm_en = {
+ .reg_off = ANACTRL_MPLL_CTRL5,
+ .shift = 30,
+ .width = 1,
+ },
+ .n2 = {
+ .reg_off = ANACTRL_MPLL_CTRL5,
+ .shift = 20,
+ .width = 9,
+ },
+ .ssen = {
+ .reg_off = ANACTRL_MPLL_CTRL5,
+ .shift = 29,
+ .width = 1,
+ },
+ .lock = &aml_clk_lock,
+ .init_regs = mpll2_init_regs,
+ .init_count = ARRAY_SIZE(mpll2_init_regs),
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll2_div",
+ .ops = &meson_clk_mpll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &mpll_prediv.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap mpll2 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_MPLL_CTRL5,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &mpll2_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct reg_sequence mpll3_init_regs[] = {
+ { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 },
+};
+
+static struct clk_regmap mpll3_div = {
+ .data = &(struct meson_clk_mpll_data){
+ .sdm = {
+ .reg_off = ANACTRL_MPLL_CTRL7,
+ .shift = 0,
+ .width = 14,
+ },
+ .sdm_en = {
+ .reg_off = ANACTRL_MPLL_CTRL7,
+ .shift = 30,
+ .width = 1,
+ },
+ .n2 = {
+ .reg_off = ANACTRL_MPLL_CTRL7,
+ .shift = 20,
+ .width = 9,
+ },
+ .ssen = {
+ .reg_off = ANACTRL_MPLL_CTRL7,
+ .shift = 29,
+ .width = 1,
+ },
+ .lock = &aml_clk_lock,
+ .init_regs = mpll3_init_regs,
+ .init_count = ARRAY_SIZE(mpll3_init_regs),
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll3_div",
+ .ops = &meson_clk_mpll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &mpll_prediv.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap mpll3 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_MPLL_CTRL7,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpll3",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &mpll3_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct reg_sequence gp0_init_regs[] = {
+ { .reg = ANACTRL_GP0PLL_CTRL0, .def = 0X08000000 },
+ { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 },
+ { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 },
+ { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x6a295c00 },
+ { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x65771290 },
+ { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a },
+ { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x54540000 }
+};
+
+static const struct pll_mult_range gp0_pll_mult_range = {
+ .min = 125,
+ .max = 250,
+};
+
+static struct clk_regmap gp0_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = ANACTRL_GP0PLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = ANACTRL_GP0PLL_CTRL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .frac = {
+ .reg_off = ANACTRL_GP0PLL_CTRL1,
+ .shift = 0,
+ .width = 17,
+ },
+ .n = {
+ .reg_off = ANACTRL_GP0PLL_CTRL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .l = {
+ .reg_off = ANACTRL_GP0PLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = ANACTRL_GP0PLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .range = &gp0_pll_mult_range,
+ .init_regs = gp0_init_regs,
+ .init_count = ARRAY_SIZE(gp0_init_regs),
+ .frac_max = 100000,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gp0_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal_24m",
+ },
+ .num_parents = 1,
+ },
+};
+
+/* The maximum frequency divider supports is 16, not 128(2^7) */
+static const struct clk_div_table gp0_pll_od_table[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 4, 16 },
+ { 5, 32 },
+ { /* sentinel */ }
+};
+
+static struct clk_regmap gp0_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = ANACTRL_GP0PLL_CTRL0,
+ .shift = 16,
+ .width = 3,
+ .table = gp0_pll_od_table,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gp0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &gp0_pll_dco.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct reg_sequence hifi_init_regs[] = {
+ { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0X08000000 },
+ { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00000000 },
+ { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
+ { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a295c00 },
+ { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
+ { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
+ { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x54540000 }
+};
+
+static const struct pll_mult_range hifi_pll_mult_range = {
+ .min = 125,
+ .max = 250,
+};
+
+static struct clk_regmap hifi_pll_dco = {
+ .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,
+ },
+ .frac = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL1,
+ .shift = 0,
+ .width = 17,
+ },
+ .n = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .l = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .range = &hifi_pll_mult_range,
+ .init_regs = hifi_init_regs,
+ .init_count = ARRAY_SIZE(hifi_init_regs),
+ .frac_max = 100000,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal_24m",
+ },
+ .num_parents = 1,
+ },
+};
+
+/* The maximum frequency divider supports is 16, not 128(2^7) */
+static const struct clk_div_table hifi_pll_od_table[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { /* sentinel */ }
+};
+
+static struct clk_regmap hifi_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 16,
+ .width = 3,
+ .table = hifi_pll_od_table,
+ .flags = CLK_DIVIDER_POWER_OF_TWO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &hifi_pll_dco.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_hw *a5_pll_hw_clks[] = {
+ [CLKID_MPLL_PREDIV] = &mpll_prediv.hw,
+ [CLKID_MPLL0_DIV] = &mpll0_div.hw,
+ [CLKID_MPLL0] = &mpll0.hw,
+ [CLKID_MPLL1_DIV] = &mpll1_div.hw,
+ [CLKID_MPLL1] = &mpll1.hw,
+ [CLKID_MPLL2_DIV] = &mpll2_div.hw,
+ [CLKID_MPLL2] = &mpll2.hw,
+ [CLKID_MPLL3_DIV] = &mpll3_div.hw,
+ [CLKID_MPLL3] = &mpll3.hw,
+ [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw,
+ [CLKID_GP0_PLL] = &gp0_pll.hw,
+ [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw,
+ [CLKID_HIFI_PLL] = &hifi_pll.hw
+};
+
+/* Convenience table to populate regmap in .probe */
+static struct clk_regmap *const a5_pll_clk_regmaps[] = {
+ &mpll0_div,
+ &mpll0,
+ &mpll1_div,
+ &mpll1,
+ &mpll2_div,
+ &mpll2,
+ &mpll3_div,
+ &mpll3,
+ &gp0_pll_dco,
+ &gp0_pll,
+ &hifi_pll_dco,
+ &hifi_pll
+};
+
+static const struct regmap_config clkc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = ANACTRL_MPLL_CTRL8,
+};
+
+static struct meson_clk_hw_data a5_pll_clks = {
+ .hws = a5_pll_hw_clks,
+ .num = ARRAY_SIZE(a5_pll_hw_clks),
+};
+
+static int aml_a5_pll_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ void __iomem *base;
+ int clkid, ret, i;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Populate regmap for the regmap backed clocks */
+ for (i = 0; i < ARRAY_SIZE(a5_pll_clk_regmaps); i++)
+ a5_pll_clk_regmaps[i]->map = regmap;
+
+ for (clkid = 0; clkid < a5_pll_clks.num; clkid++) {
+ /* array might be sparse */
+ if (!a5_pll_clks.hws[clkid])
+ continue;
+
+ ret = devm_clk_hw_register(dev, a5_pll_clks.hws[clkid]);
+ if (ret) {
+ dev_err(dev, "Clock registration failed\n");
+ return ret;
+ }
+ }
+
+ return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
+ &a5_pll_clks);
+}
+
+static const struct of_device_id a5_pll_clkc_match_table[] = {
+ {
+ .compatible = "amlogic,a5-pll-clkc",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, a5_pll_clkc_match_table);
+
+static struct platform_driver a5_pll_driver = {
+ .probe = aml_a5_pll_probe,
+ .driver = {
+ .name = "a5-pll-clkc",
+ .of_match_table = a5_pll_clkc_match_table,
+ },
+};
+module_platform_driver(a5_pll_driver);
+
+MODULE_DESCRIPTION("Amlogic A5 PLL Clock Controller driver");
+MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
+MODULE_LICENSE("GPL");
--
2.37.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
` (3 preceding siblings ...)
2024-09-14 5:25 ` [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock Xianwei Zhao via B4 Relay
@ 2024-09-14 5:25 ` Xianwei Zhao via B4 Relay
2024-09-24 15:09 ` Jerome Brunet
4 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao via B4 Relay @ 2024-09-14 5:25 UTC (permalink / raw)
To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chuan Liu,
Kevin Hilman, Martin Blumenstingl
Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
linux-arm-kernel, Xianwei Zhao
From: Chuan Liu <chuan.liu@amlogic.com>
Add the peripherals clock controller driver in the A5 SoC family.
Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
drivers/clk/meson/Kconfig | 14 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a5-peripherals.c | 1471 ++++++++++++++++++++++++++++++++++++
3 files changed, 1486 insertions(+)
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 2a713276e46c..21845edcd8ef 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -146,6 +146,20 @@ config COMMON_CLK_A5_PLL
Say Y if you want the board to work, because PLLs are the parent
of most peripherals.
+config COMMON_CLK_A5_PERIPHERALS
+ tristate "Amlogic A5 peripherals clock controller"
+ depends on ARM64
+ default y
+ imply ARM_SCMI_PROTOCOL
+ imply COMMON_CLK_SCMI
+ imply COMMON_CLK_A5_PLL
+ select COMMON_CLK_MESON_REGMAP
+ select COMMON_CLK_MESON_DUALDIV
+ select COMMON_CLK_MESON_CLKC_UTILS
+ help
+ Support for the Peripherals clock controller on Amlogic AV40x device,
+ AKA A5. Say Y if you want the peripherals clock to work.
+
config COMMON_CLK_C3_PLL
tristate "Amlogic C3 PLL clock controller"
depends on ARM64
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index fc4b8a723145..58236c6e8377 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
+obj-$(CONFIG_COMMON_CLK_A5_PERIPHERALS) += a5-peripherals.o
obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
diff --git a/drivers/clk/meson/a5-peripherals.c b/drivers/clk/meson/a5-peripherals.c
new file mode 100644
index 000000000000..c28da340a5af
--- /dev/null
+++ b/drivers/clk/meson/a5-peripherals.c
@@ -0,0 +1,1471 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Amlogic A5 Peripherals Clock Controller Driver
+ *
+ * Copyright (c) 2024 Amlogic, inc.
+ * Author: Chuan Liu <chuan.liu@amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+#include "meson-clkc-utils.h"
+#include <dt-bindings/clock/amlogic,a5-peripherals-clkc.h>
+
+#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x8
+#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0xc
+#define CLKCTRL_RTC_CTRL 0x10
+#define CLKCTRL_SYS_CLK_EN0_REG0 0x44
+#define CLKCTRL_SYS_CLK_EN0_REG1 0x48
+#define CLKCTRL_DSPA_CLK_CTRL0 0x9c
+#define CLKCTRL_CLK12_24_CTRL 0xa8
+#define CLKCTRL_AXI_CLK_EN0 0xac
+#define CLKCTRL_TS_CLK_CTRL 0x158
+#define CLKCTRL_ETH_CLK_CTRL 0x164
+#define CLKCTRL_NAND_CLK_CTRL 0x168
+#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c
+#define CLKCTRL_SPICC_CLK_CTRL 0x174
+#define CLKCTRL_GEN_CLK_CTRL 0x178
+#define CLKCTRL_SAR_CLK_CTRL0 0x17c
+#define CLKCTRL_PWM_CLK_AB_CTRL 0x180
+#define CLKCTRL_PWM_CLK_CD_CTRL 0x184
+#define CLKCTRL_PWM_CLK_EF_CTRL 0x188
+#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c
+#define CLKCTRL_NNA_CLK_CNTL 0x220
+
+static struct clk_regmap rtc_xtal_clkin = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_xtal_clkin",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "oscin",
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct meson_clk_dualdiv_param rtc_32k_div_table[] = {
+ { 733, 732, 8, 11, 1 },
+ { /* sentinel */ }
+};
+
+static struct clk_regmap rtc_32k_div = {
+ .data = &(struct meson_clk_dualdiv_data) {
+ .n1 = {
+ .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
+ .shift = 0,
+ .width = 12,
+ },
+ .n2 = {
+ .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
+ .shift = 12,
+ .width = 12,
+ },
+ .m1 = {
+ .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
+ .shift = 0,
+ .width = 12,
+ },
+ .m2 = {
+ .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
+ .shift = 12,
+ .width = 12,
+ },
+ .dual = {
+ .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .table = rtc_32k_div_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_32k_div",
+ .ops = &meson_clk_dualdiv_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_xtal_clkin.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct clk_parent_data rtc_32k_mux_parent_data[] = {
+ { .hw = &rtc_32k_div.hw },
+ { .hw = &rtc_xtal_clkin.hw }
+};
+
+static struct clk_regmap rtc_32k_mux = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_RTC_BY_OSCIN_CTRL1,
+ .mask = 0x1,
+ .shift = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_32k_mux",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = rtc_32k_mux_parent_data,
+ .num_parents = ARRAY_SIZE(rtc_32k_mux_parent_data),
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap rtc_32k = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
+ .bit_idx = 30,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_32k",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_32k_mux.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data rtc_clk_mux_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .hw = &rtc_32k.hw },
+ { .fw_name = "pad_osc" }
+};
+
+static struct clk_regmap rtc_clk = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_RTC_CTRL,
+ .mask = 0x3,
+ .shift = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_clk",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = rtc_clk_mux_parent_data,
+ .num_parents = ARRAY_SIZE(rtc_clk_mux_parent_data),
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+#define A4_CLK_GATE(_name, _reg, _bit, _fw_name, _ops, _flags) \
+struct clk_regmap _name = { \
+ .data = &(struct clk_regmap_gate_data){ \
+ .offset = (_reg), \
+ .bit_idx = (_bit), \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = #_name, \
+ .ops = _ops, \
+ .parent_data = &(const struct clk_parent_data) { \
+ .fw_name = #_fw_name, \
+ }, \
+ .num_parents = 1, \
+ .flags = (_flags), \
+ }, \
+}
+
+#define A4_SYS_GATE(_name, _reg, _bit, _flags) \
+ A4_CLK_GATE(_name, _reg, _bit, sysclk, \
+ &clk_regmap_gate_ops, _flags)
+
+#define A4_SYS_GATE_RO(_name, _reg, _bit) \
+ A4_CLK_GATE(_name, _reg, _bit, sysclk, \
+ &clk_regmap_gate_ro_ops, 0)
+
+static A4_SYS_GATE(sys_reset_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 1, 0);
+static A4_SYS_GATE(sys_pwr_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 3, 0);
+static A4_SYS_GATE(sys_pad_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 4, 0);
+static A4_SYS_GATE(sys_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 5, 0);
+static A4_SYS_GATE(sys_ts_pll, CLKCTRL_SYS_CLK_EN0_REG0, 6, 0);
+
+/*
+ * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that
+ * access the AXI bus.
+ */
+static A4_SYS_GATE(sys_dev_arb, CLKCTRL_SYS_CLK_EN0_REG0, 7, 0);
+
+/*
+ * FIXME: sys_mmc_pclk provides the clock for the DDR PHY, DDR will only be
+ * initialized in bl2, and this clock should not be touched in linux.
+ */
+static A4_SYS_GATE_RO(sys_mmc_pclk, CLKCTRL_SYS_CLK_EN0_REG0, 8);
+static A4_SYS_GATE(sys_mailbox, CLKCTRL_SYS_CLK_EN0_REG0, 10, 0);
+
+/*
+ * NOTE: sys_cpu_ctrl provides the clock for CPU controller. After clock is
+ * disabled, cpu_clk and other key CPU-related configurations cannot take effect.
+ */
+static A4_SYS_GATE(sys_cpu_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL);
+static A4_SYS_GATE(sys_jtag_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 12, 0);
+static A4_SYS_GATE(sys_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 13, 0);
+
+/*
+ * NOTE: sys_irq_ctrl provides the clock for IRQ controller. The IRQ controller
+ * collects and distributes the interrupt signal to the GIC, PWR_CTRL, and
+ * AOCPU. If the clock is disabled, interrupt-related functions will occurs an
+ * exception.
+ */
+static A4_SYS_GATE(sys_irq_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL);
+static A4_SYS_GATE(sys_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 15, 0);
+static A4_SYS_GATE(sys_rom, CLKCTRL_SYS_CLK_EN0_REG0, 16, 0);
+static A4_SYS_GATE(sys_cpu_apb, CLKCTRL_SYS_CLK_EN0_REG0, 18, 0);
+static A4_SYS_GATE(sys_rsa, CLKCTRL_SYS_CLK_EN0_REG0, 19, 0);
+static A4_SYS_GATE(sys_sar_adc, CLKCTRL_SYS_CLK_EN0_REG0, 20, 0);
+static A4_SYS_GATE(sys_startup, CLKCTRL_SYS_CLK_EN0_REG0, 21, 0);
+static A4_SYS_GATE(sys_secure, CLKCTRL_SYS_CLK_EN0_REG0, 22, 0);
+static A4_SYS_GATE(sys_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 23, 0);
+static A4_SYS_GATE(sys_dspa, CLKCTRL_SYS_CLK_EN0_REG0, 24, 0);
+static A4_SYS_GATE(sys_nna, CLKCTRL_SYS_CLK_EN0_REG0, 25, 0);
+static A4_SYS_GATE(sys_eth_mac, CLKCTRL_SYS_CLK_EN0_REG0, 26, 0);
+
+/*
+ * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller).
+ * After clock is disabled, The GIC cannot work properly. At present, the driver
+ * used by our GIC is the public driver in kernel, and there is no management
+ * clock in the driver.
+ */
+static A4_SYS_GATE(sys_gic, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL);
+static A4_SYS_GATE(sys_rama, CLKCTRL_SYS_CLK_EN0_REG0, 28, 0);
+
+/*
+ * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network
+ * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC,
+ * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the
+ * system. After clock is disabled, The NIC cannot work.
+ */
+static A4_SYS_GATE(sys_big_nic, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL);
+static A4_SYS_GATE(sys_ramb, CLKCTRL_SYS_CLK_EN0_REG0, 30, 0);
+static A4_SYS_GATE(sys_audio_top, CLKCTRL_SYS_CLK_EN0_REG1, 0, 0);
+static A4_SYS_GATE(sys_audio_vad, CLKCTRL_SYS_CLK_EN0_REG1, 1, 0);
+static A4_SYS_GATE(sys_usb, CLKCTRL_SYS_CLK_EN0_REG1, 2, 0);
+static A4_SYS_GATE(sys_sd_emmc_a, CLKCTRL_SYS_CLK_EN0_REG1, 3, 0);
+static A4_SYS_GATE(sys_sd_emmc_c, CLKCTRL_SYS_CLK_EN0_REG1, 4, 0);
+static A4_SYS_GATE(sys_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG1, 5, 0);
+static A4_SYS_GATE(sys_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG1, 6, 0);
+static A4_SYS_GATE(sys_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG1, 7, 0);
+static A4_SYS_GATE(sys_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG1, 8, 0);
+static A4_SYS_GATE(sys_spicc_1, CLKCTRL_SYS_CLK_EN0_REG1, 9, 0);
+static A4_SYS_GATE(sys_spicc_0, CLKCTRL_SYS_CLK_EN0_REG1, 10, 0);
+static A4_SYS_GATE(sys_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 11, 0);
+static A4_SYS_GATE(sys_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 12, 0);
+static A4_SYS_GATE(sys_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 13, 0);
+static A4_SYS_GATE(sys_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 14, 0);
+static A4_SYS_GATE(sys_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 15, 0);
+static A4_SYS_GATE(sys_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 16, 0);
+static A4_SYS_GATE(sys_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 17, 0);
+static A4_SYS_GATE(sys_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG1, 18, 0);
+static A4_SYS_GATE(sys_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG1, 19, 0);
+static A4_SYS_GATE(sys_rtc, CLKCTRL_SYS_CLK_EN0_REG1, 21, 0);
+
+#define A4_AXI_GATE(_name, _reg, _bit, _flags) \
+ A4_CLK_GATE(_name, _reg, _bit, axiclk, \
+ &clk_regmap_gate_ops, _flags)
+
+static A4_AXI_GATE(axi_audio_vad, CLKCTRL_AXI_CLK_EN0, 0, 0);
+static A4_AXI_GATE(axi_audio_top, CLKCTRL_AXI_CLK_EN0, 1, 0);
+
+/*
+ * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After
+ * clock is disabled, The NIC cannot work.
+ */
+static A4_AXI_GATE(axi_sys_nic, CLKCTRL_AXI_CLK_EN0, 2, CLK_IS_CRITICAL);
+static A4_AXI_GATE(axi_ramb, CLKCTRL_AXI_CLK_EN0, 5, 0);
+static A4_AXI_GATE(axi_rama, CLKCTRL_AXI_CLK_EN0, 6, 0);
+
+/*
+ * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses
+ * the DDR. After clock is disabled, The CPU will not have access to the DDR.
+ */
+static A4_AXI_GATE(axi_cpu_dmc, CLKCTRL_AXI_CLK_EN0, 7, CLK_IS_CRITICAL);
+static A4_AXI_GATE(axi_nna, CLKCTRL_AXI_CLK_EN0, 12, 0);
+
+/*
+ * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
+ * sec_top, USB, Audio) to access the AXI bus of the DDR.
+ */
+static A4_AXI_GATE(axi_dev1_dmc, CLKCTRL_AXI_CLK_EN0, 13, 0);
+
+/*
+ * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
+ * to access the AXI bus of the DDR.
+ */
+static A4_AXI_GATE(axi_dev0_dmc, CLKCTRL_AXI_CLK_EN0, 14, 0);
+static A4_AXI_GATE(axi_dsp_dmc, CLKCTRL_AXI_CLK_EN0, 15, 0);
+
+static struct clk_regmap clk_12_24m_in = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_CLK12_24_CTRL,
+ .bit_idx = 11,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "clk_12_24m_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal_24m",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap clk_12_24m = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_CLK12_24_CTRL,
+ .shift = 10,
+ .width = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "clk_12_24m",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &clk_12_24m_in.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+/* FIXME: set value 0 will div by 2 like value 1 */
+static struct clk_regmap fclk_25m_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_CLK12_24_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "fclk_25m_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fix",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_25m = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_CLK12_24_CTRL,
+ .bit_idx = 12,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "fclk_25m",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_25m_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/*
+ * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk)
+ * is manged by clock measures module. Their hardware are out of clock tree.
+ * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
+ *
+ * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
+ * arbitrarily. gp1 is read-only in the kernel and is only open for debug purposes.
+ */
+static u32 gen_parent_table[] = { 0, 1, 2, 6, 7, 17, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28};
+
+static const struct clk_parent_data gen_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .hw = &rtc_clk.hw },
+ { .fw_name = "sysplldiv16" },
+ { .fw_name = "gp1" },
+ { .fw_name = "hifi" },
+ { .fw_name = "cpudiv16" },
+ { .fw_name = "fdiv2" },
+ { .fw_name = "fdiv2p5" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "fdiv4" },
+ { .fw_name = "fdiv5" },
+ { .fw_name = "fdiv7" },
+ { .fw_name = "mpll0" },
+ { .fw_name = "mpll1" },
+ { .fw_name = "mpll2" },
+ { .fw_name = "mpll3" }
+};
+
+static struct clk_regmap gen_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_GEN_CLK_CTRL,
+ .mask = 0x1f,
+ .shift = 12,
+ .table = gen_parent_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gen_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = gen_parent_data,
+ .num_parents = ARRAY_SIZE(gen_parent_data),
+ },
+};
+
+static struct clk_regmap gen_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_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 *[]) {
+ &gen_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gen = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_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 *[]) {
+ &gen_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data saradc_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .fw_name = "sysclk" }
+};
+
+static struct clk_regmap saradc_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_SAR_CLK_CTRL0,
+ .mask = 0x1,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "saradc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = saradc_parent_data,
+ .num_parents = ARRAY_SIZE(saradc_parent_data),
+ },
+};
+
+static struct clk_regmap saradc_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_SAR_CLK_CTRL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "saradc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &saradc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap saradc = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_SAR_CLK_CTRL0,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "saradc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &saradc_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data pwm_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .hw = &rtc_clk.hw },
+ { .fw_name = "fdiv4" },
+ { .fw_name = "fdiv3" }
+};
+
+#define AML_PWM_CLK_MUX(_name, _reg, _shift) { \
+ .data = &(struct clk_regmap_mux_data) { \
+ .offset = _reg, \
+ .mask = 0x3, \
+ .shift = _shift, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = #_name "_sel", \
+ .ops = &clk_regmap_mux_ops, \
+ .parent_data = pwm_parent_data, \
+ .num_parents = ARRAY_SIZE(pwm_parent_data), \
+ }, \
+}
+
+#define AML_PWM_CLK_DIV(_name, _reg, _shift) { \
+ .data = &(struct clk_regmap_div_data) { \
+ .offset = _reg, \
+ .shift = _shift, \
+ .width = 8, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = #_name "_div", \
+ .ops = &clk_regmap_divider_ops, \
+ .parent_names = (const char *[]) { #_name "_sel" },\
+ .num_parents = 1, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+}
+
+#define AML_PWM_CLK_GATE(_name, _reg, _bit) { \
+ .data = &(struct clk_regmap_gate_data) { \
+ .offset = _reg, \
+ .bit_idx = _bit, \
+ }, \
+ .hw.init = &(struct clk_init_data) { \
+ .name = #_name, \
+ .ops = &clk_regmap_gate_ops, \
+ .parent_names = (const char *[]) { #_name "_div" },\
+ .num_parents = 1, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+}
+
+static struct clk_regmap pwm_a_sel =
+ AML_PWM_CLK_MUX(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 9);
+static struct clk_regmap pwm_a_div =
+ AML_PWM_CLK_DIV(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 0);
+static struct clk_regmap pwm_a =
+ AML_PWM_CLK_GATE(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 8);
+
+static struct clk_regmap pwm_b_sel =
+ AML_PWM_CLK_MUX(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 25);
+static struct clk_regmap pwm_b_div =
+ AML_PWM_CLK_DIV(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 16);
+static struct clk_regmap pwm_b =
+ AML_PWM_CLK_GATE(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 24);
+
+static struct clk_regmap pwm_c_sel =
+ AML_PWM_CLK_MUX(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 9);
+static struct clk_regmap pwm_c_div =
+ AML_PWM_CLK_DIV(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 0);
+static struct clk_regmap pwm_c =
+ AML_PWM_CLK_GATE(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 8);
+
+static struct clk_regmap pwm_d_sel =
+ AML_PWM_CLK_MUX(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 25);
+static struct clk_regmap pwm_d_div =
+ AML_PWM_CLK_DIV(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 16);
+static struct clk_regmap pwm_d =
+ AML_PWM_CLK_GATE(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 24);
+
+static struct clk_regmap pwm_e_sel =
+ AML_PWM_CLK_MUX(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 9);
+static struct clk_regmap pwm_e_div =
+ AML_PWM_CLK_DIV(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 0);
+static struct clk_regmap pwm_e =
+ AML_PWM_CLK_GATE(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 8);
+
+static struct clk_regmap pwm_f_sel =
+ AML_PWM_CLK_MUX(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 25);
+static struct clk_regmap pwm_f_div =
+ AML_PWM_CLK_DIV(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 16);
+static struct clk_regmap pwm_f =
+ AML_PWM_CLK_GATE(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 24);
+
+static struct clk_regmap pwm_g_sel =
+ AML_PWM_CLK_MUX(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 9);
+static struct clk_regmap pwm_g_div =
+ AML_PWM_CLK_DIV(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 0);
+static struct clk_regmap pwm_g =
+ AML_PWM_CLK_GATE(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 8);
+
+static struct clk_regmap pwm_h_sel =
+ AML_PWM_CLK_MUX(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25);
+static struct clk_regmap pwm_h_div =
+ AML_PWM_CLK_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16);
+static struct clk_regmap pwm_h =
+ AML_PWM_CLK_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24);
+
+/* Channel 7 is gp1. */
+static const struct clk_parent_data spicc_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .fw_name = "sysclk" },
+ { .fw_name = "fdiv4" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "fdiv2" },
+ { .fw_name = "fdiv5" },
+ { .fw_name = "fdiv7" }
+};
+
+static struct clk_regmap spicc_0_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_0_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = spicc_parent_data,
+ .num_parents = ARRAY_SIZE(spicc_parent_data),
+ },
+};
+
+static struct clk_regmap spicc_0_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .shift = 0,
+ .width = 6,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_0_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_0_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spicc_0 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .bit_idx = 6,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_0",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_0_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spicc_1_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 23,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_1_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = spicc_parent_data,
+ .num_parents = ARRAY_SIZE(spicc_parent_data),
+ },
+};
+
+static struct clk_regmap spicc_1_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .shift = 16,
+ .width = 6,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_1_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_1_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spicc_1 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_SPICC_CLK_CTRL,
+ .bit_idx = 22,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc_1",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_1_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data emmc_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .fw_name = "fdiv2" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "hifi" },
+ { .fw_name = "fdiv2p5" },
+ { .fw_name = "mpll2" },
+ { .fw_name = "mpll3" },
+ { .fw_name = "gp0" }
+};
+
+static struct clk_regmap sd_emmc_a_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_a_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = emmc_parent_data,
+ .num_parents = ARRAY_SIZE(emmc_parent_data),
+ },
+};
+
+static struct clk_regmap sd_emmc_a_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
+ .shift = 0,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_a_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_a_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sd_emmc_a = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
+ .bit_idx = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_a",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_a_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sd_emmc_c_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_NAND_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_c_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = emmc_parent_data,
+ .num_parents = ARRAY_SIZE(emmc_parent_data),
+ },
+};
+
+static struct clk_regmap sd_emmc_c_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_NAND_CLK_CTRL,
+ .shift = 0,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_c_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_c_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sd_emmc_c = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_NAND_CLK_CTRL,
+ .bit_idx = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc_c",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_c_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap ts_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_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 = "oscin",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap ts = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_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 *[]) {
+ &ts_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor eth_125m_div = {
+ .mult = 1,
+ .div = 8,
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_125m_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fdiv2",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap eth_125m = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_ETH_CLK_CTRL,
+ .bit_idx = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_125m",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ ð_125m_div.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap eth_rmii_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_ETH_CLK_CTRL,
+ .shift = 0,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_rmii_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fdiv2",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap eth_rmii = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_ETH_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_rmii",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ ð_rmii_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/* Channel 6 is gp1. */
+static u32 dspa_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
+
+static const struct clk_parent_data dspa_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .fw_name = "fdiv2p5" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "rtc" },
+ { .fw_name = "hifi" },
+ { .fw_name = "fdiv4" },
+ { .hw = &rtc_clk.hw }
+};
+
+static struct clk_regmap dspa_0_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 10,
+ .table = dspa_parent_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_0_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dspa_parent_data,
+ .num_parents = ARRAY_SIZE(dspa_parent_data),
+ },
+};
+
+static struct clk_regmap dspa_0_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .shift = 0,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_0_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_0_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa_0 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .bit_idx = 13,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_0",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_0_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa_1_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 26,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_1_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dspa_parent_data,
+ .num_parents = ARRAY_SIZE(dspa_parent_data),
+ },
+};
+
+static struct clk_regmap dspa_1_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .shift = 16,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_1_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_1_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa_1 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .bit_idx = 29,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_1",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_1_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = CLKCTRL_DSPA_CLK_CTRL0,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_0.hw,
+ &dspa_1.hw
+ },
+ .num_parents = 2,
+ /*
+ * NOTE: This level of mux is "no glitch mux", and mux_0
+ * (here dspa_0) is not only the clock source for mux, but also
+ * provides a working clock for "no glitch mux". "no glitch mux"
+ * can be switched only when mux_0 has a clock input. Therefore,
+ * add flag CLK_OPS_PARENT_ENABLE to ensure that mux_0 has clock
+ * when "no glitch mux" works.
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ },
+};
+
+/* Channel 6 is gp1. */
+static u32 nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
+
+static const struct clk_parent_data nna_parent_data[] = {
+ { .fw_name = "oscin" },
+ { .fw_name = "fdiv2p5" },
+ { .fw_name = "fdiv4" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "fdiv5" },
+ { .fw_name = "fdiv2" },
+ { .fw_name = "hifi" }
+};
+
+static struct clk_regmap nna_core_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .mask = 0x7,
+ .shift = 9,
+ .table = nna_parent_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_core_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = nna_parent_data,
+ .num_parents = ARRAY_SIZE(nna_parent_data),
+ },
+};
+
+static struct clk_regmap nna_core_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .shift = 0,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_core_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &nna_core_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap nna_core = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_core",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &nna_core_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap nna_axi_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .mask = 0x7,
+ .shift = 25,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_axi_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = nna_parent_data,
+ .num_parents = ARRAY_SIZE(nna_parent_data),
+ },
+};
+
+static struct clk_regmap nna_axi_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .shift = 16,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_axi_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &nna_axi_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap nna_axi = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = CLKCTRL_NNA_CLK_CNTL,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "nna_axi",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &nna_axi_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_hw *a5_periphs_hw_clks[] = {
+ [CLKID_RTC_XTAL_CLKIN] = &rtc_xtal_clkin.hw,
+ [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw,
+ [CLKID_RTC_32K_MUX] = &rtc_32k_mux.hw,
+ [CLKID_RTC_32K] = &rtc_32k.hw,
+ [CLKID_RTC_CLK] = &rtc_clk.hw,
+ [CLKID_SYS_RESET_CTRL] = &sys_reset_ctrl.hw,
+ [CLKID_SYS_PWR_CTRL] = &sys_pwr_ctrl.hw,
+ [CLKID_SYS_PAD_CTRL] = &sys_pad_ctrl.hw,
+ [CLKID_SYS_CTRL] = &sys_ctrl.hw,
+ [CLKID_SYS_TS_PLL] = &sys_ts_pll.hw,
+ [CLKID_SYS_DEV_ARB] = &sys_dev_arb.hw,
+ [CLKID_SYS_MMC_PCLK] = &sys_mmc_pclk.hw,
+ [CLKID_SYS_MAILBOX] = &sys_mailbox.hw,
+ [CLKID_SYS_CPU_CTRL] = &sys_cpu_ctrl.hw,
+ [CLKID_SYS_JTAG_CTRL] = &sys_jtag_ctrl.hw,
+ [CLKID_SYS_IR_CTRL] = &sys_ir_ctrl.hw,
+ [CLKID_SYS_IRQ_CTRL] = &sys_irq_ctrl.hw,
+ [CLKID_SYS_MSR_CLK] = &sys_msr_clk.hw,
+ [CLKID_SYS_ROM] = &sys_rom.hw,
+ [CLKID_SYS_CPU_ARB] = &sys_cpu_apb.hw,
+ [CLKID_SYS_RSA] = &sys_rsa.hw,
+ [CLKID_SYS_SAR_ADC] = &sys_sar_adc.hw,
+ [CLKID_SYS_STARTUP] = &sys_startup.hw,
+ [CLKID_SYS_SECURE] = &sys_secure.hw,
+ [CLKID_SYS_SPIFC] = &sys_spifc.hw,
+ [CLKID_SYS_DSPA] = &sys_dspa.hw,
+ [CLKID_SYS_NNA] = &sys_nna.hw,
+ [CLKID_SYS_ETH_MAC] = &sys_eth_mac.hw,
+ [CLKID_SYS_GIC] = &sys_gic.hw,
+ [CLKID_SYS_RAMA] = &sys_rama.hw,
+ [CLKID_SYS_BIG_NIC] = &sys_big_nic.hw,
+ [CLKID_SYS_RAMB] = &sys_ramb.hw,
+ [CLKID_SYS_AUDIO_TOP] = &sys_audio_top.hw,
+ [CLKID_SYS_AUDIO_VAD] = &sys_audio_vad.hw,
+ [CLKID_SYS_USB] = &sys_usb.hw,
+ [CLKID_SYS_SD_EMMC_A] = &sys_sd_emmc_a.hw,
+ [CLKID_SYS_SD_EMMC_C] = &sys_sd_emmc_c.hw,
+ [CLKID_SYS_PWM_AB] = &sys_pwm_ab.hw,
+ [CLKID_SYS_PWM_CD] = &sys_pwm_cd.hw,
+ [CLKID_SYS_PWM_EF] = &sys_pwm_ef.hw,
+ [CLKID_SYS_PWM_GH] = &sys_pwm_gh.hw,
+ [CLKID_SYS_SPICC_1] = &sys_spicc_1.hw,
+ [CLKID_SYS_SPICC_0] = &sys_spicc_0.hw,
+ [CLKID_SYS_UART_A] = &sys_uart_a.hw,
+ [CLKID_SYS_UART_B] = &sys_uart_b.hw,
+ [CLKID_SYS_UART_C] = &sys_uart_c.hw,
+ [CLKID_SYS_UART_D] = &sys_uart_d.hw,
+ [CLKID_SYS_UART_E] = &sys_uart_e.hw,
+ [CLKID_SYS_I2C_M_A] = &sys_i2c_m_a.hw,
+ [CLKID_SYS_I2C_M_B] = &sys_i2c_m_b.hw,
+ [CLKID_SYS_I2C_M_C] = &sys_i2c_m_c.hw,
+ [CLKID_SYS_I2C_M_D] = &sys_i2c_m_d.hw,
+ [CLKID_SYS_RTC] = &sys_rtc.hw,
+ [CLKID_AXI_AUDIO_VAD] = &axi_audio_vad.hw,
+ [CLKID_AXI_AUDIO_TOP] = &axi_audio_top.hw,
+ [CLKID_AXI_SYS_NIC] = &axi_sys_nic.hw,
+ [CLKID_AXI_RAMB] = &axi_ramb.hw,
+ [CLKID_AXI_RAMA] = &axi_rama.hw,
+ [CLKID_AXI_CPU_DMC] = &axi_cpu_dmc.hw,
+ [CLKID_AXI_NNA] = &axi_nna.hw,
+ [CLKID_AXI_DEV1_DMC] = &axi_dev1_dmc.hw,
+ [CLKID_AXI_DEV0_DMC] = &axi_dev0_dmc.hw,
+ [CLKID_AXI_DSP_DMC] = &axi_dsp_dmc.hw,
+ [CLKID_12_24M_IN] = &clk_12_24m_in.hw,
+ [CLKID_12M_24M] = &clk_12_24m.hw,
+ [CLKID_FCLK_25M_DIV] = &fclk_25m_div.hw,
+ [CLKID_FCLK_25M] = &fclk_25m.hw,
+ [CLKID_GEN_SEL] = &gen_sel.hw,
+ [CLKID_GEN_DIV] = &gen_div.hw,
+ [CLKID_GEN] = &gen.hw,
+ [CLKID_SARADC_SEL] = &saradc_sel.hw,
+ [CLKID_SARADC_DIV] = &saradc_div.hw,
+ [CLKID_SARADC] = &saradc.hw,
+ [CLKID_PWM_A_SEL] = &pwm_a_sel.hw,
+ [CLKID_PWM_A_DIV] = &pwm_a_div.hw,
+ [CLKID_PWM_A] = &pwm_a.hw,
+ [CLKID_PWM_B_SEL] = &pwm_b_sel.hw,
+ [CLKID_PWM_B_DIV] = &pwm_b_div.hw,
+ [CLKID_PWM_B] = &pwm_b.hw,
+ [CLKID_PWM_C_SEL] = &pwm_c_sel.hw,
+ [CLKID_PWM_C_DIV] = &pwm_c_div.hw,
+ [CLKID_PWM_C] = &pwm_c.hw,
+ [CLKID_PWM_D_SEL] = &pwm_d_sel.hw,
+ [CLKID_PWM_D_DIV] = &pwm_d_div.hw,
+ [CLKID_PWM_D] = &pwm_d.hw,
+ [CLKID_PWM_E_SEL] = &pwm_e_sel.hw,
+ [CLKID_PWM_E_DIV] = &pwm_e_div.hw,
+ [CLKID_PWM_E] = &pwm_e.hw,
+ [CLKID_PWM_F_SEL] = &pwm_f_sel.hw,
+ [CLKID_PWM_F_DIV] = &pwm_f_div.hw,
+ [CLKID_PWM_F] = &pwm_f.hw,
+ [CLKID_PWM_G_SEL] = &pwm_g_sel.hw,
+ [CLKID_PWM_G_DIV] = &pwm_g_div.hw,
+ [CLKID_PWM_G] = &pwm_g.hw,
+ [CLKID_PWM_H_SEL] = &pwm_h_sel.hw,
+ [CLKID_PWM_H_DIV] = &pwm_h_div.hw,
+ [CLKID_PWM_H] = &pwm_h.hw,
+ [CLKID_SPICC_0_SEL] = &spicc_0_sel.hw,
+ [CLKID_SPICC_0_DIV] = &spicc_0_div.hw,
+ [CLKID_SPICC_0] = &spicc_0.hw,
+ [CLKID_SPICC_1_SEL] = &spicc_1_sel.hw,
+ [CLKID_SPICC_1_DIV] = &spicc_1_div.hw,
+ [CLKID_SPICC_1] = &spicc_1.hw,
+ [CLKID_SD_EMMC_A_SEL] = &sd_emmc_a_sel.hw,
+ [CLKID_SD_EMMC_A_DIV] = &sd_emmc_a_div.hw,
+ [CLKID_SD_EMMC_A] = &sd_emmc_a.hw,
+ [CLKID_SD_EMMC_C_SEL] = &sd_emmc_c_sel.hw,
+ [CLKID_SD_EMMC_C_DIV] = &sd_emmc_c_div.hw,
+ [CLKID_SD_EMMC_C] = &sd_emmc_c.hw,
+ [CLKID_TS_DIV] = &ts_div.hw,
+ [CLKID_TS] = &ts.hw,
+ [CLKID_ETH_125M_DIV] = ð_125m_div.hw,
+ [CLKID_ETH_125M] = ð_125m.hw,
+ [CLKID_ETH_RMII_DIV] = ð_rmii_div.hw,
+ [CLKID_ETH_RMII] = ð_rmii.hw,
+ [CLKID_DSPA_0_SEL] = &dspa_0_sel.hw,
+ [CLKID_DSPA_0_DIV] = &dspa_0_div.hw,
+ [CLKID_DSPA_0] = &dspa_0.hw,
+ [CLKID_DSPA_1_SEL] = &dspa_1_sel.hw,
+ [CLKID_DSPA_1_DIV] = &dspa_1_div.hw,
+ [CLKID_DSPA_1] = &dspa_1.hw,
+ [CLKID_DSPA] = &dspa.hw,
+ [CLKID_NNA_CORE_SEL] = &nna_core_sel.hw,
+ [CLKID_NNA_CORE_DIV] = &nna_core_div.hw,
+ [CLKID_NNA_CORE] = &nna_core.hw,
+ [CLKID_NNA_AXI_SEL] = &nna_axi_sel.hw,
+ [CLKID_NNA_AXI_DIV] = &nna_axi_div.hw,
+ [CLKID_NNA_AXI] = &nna_axi.hw,
+};
+
+/* Convenience table to populate regmap in .probe */
+static struct clk_regmap *const a5_periphs_clk_regmaps[] = {
+ &rtc_xtal_clkin,
+ &rtc_32k_div,
+ &rtc_32k_mux,
+ &rtc_32k,
+ &rtc_clk,
+ &sys_reset_ctrl,
+ &sys_pwr_ctrl,
+ &sys_pad_ctrl,
+ &sys_ctrl,
+ &sys_ts_pll,
+ &sys_dev_arb,
+ &sys_mmc_pclk,
+ &sys_mailbox,
+ &sys_cpu_ctrl,
+ &sys_jtag_ctrl,
+ &sys_ir_ctrl,
+ &sys_irq_ctrl,
+ &sys_msr_clk,
+ &sys_rom,
+ &sys_cpu_apb,
+ &sys_rsa,
+ &sys_sar_adc,
+ &sys_startup,
+ &sys_secure,
+ &sys_spifc,
+ &sys_dspa,
+ &sys_nna,
+ &sys_eth_mac,
+ &sys_gic,
+ &sys_rama,
+ &sys_big_nic,
+ &sys_ramb,
+ &sys_audio_top,
+ &sys_audio_vad,
+ &sys_usb,
+ &sys_sd_emmc_a,
+ &sys_sd_emmc_c,
+ &sys_pwm_ab,
+ &sys_pwm_cd,
+ &sys_pwm_ef,
+ &sys_pwm_gh,
+ &sys_spicc_1,
+ &sys_spicc_0,
+ &sys_uart_a,
+ &sys_uart_b,
+ &sys_uart_c,
+ &sys_uart_d,
+ &sys_uart_e,
+ &sys_i2c_m_a,
+ &sys_i2c_m_b,
+ &sys_i2c_m_c,
+ &sys_i2c_m_d,
+ &sys_rtc,
+ &axi_audio_vad,
+ &axi_audio_top,
+ &axi_sys_nic,
+ &axi_ramb,
+ &axi_rama,
+ &axi_cpu_dmc,
+ &axi_nna,
+ &axi_dev1_dmc,
+ &axi_dev0_dmc,
+ &axi_dsp_dmc,
+ &clk_12_24m_in,
+ &clk_12_24m,
+ &fclk_25m_div,
+ &fclk_25m,
+ &gen_sel,
+ &gen_div,
+ &gen,
+ &saradc_sel,
+ &saradc_div,
+ &saradc,
+ &pwm_a_sel,
+ &pwm_a_div,
+ &pwm_a,
+ &pwm_b_sel,
+ &pwm_b_div,
+ &pwm_b,
+ &pwm_c_sel,
+ &pwm_c_div,
+ &pwm_c,
+ &pwm_d_sel,
+ &pwm_d_div,
+ &pwm_d,
+ &pwm_e_sel,
+ &pwm_e_div,
+ &pwm_e,
+ &pwm_f_sel,
+ &pwm_f_div,
+ &pwm_f,
+ &pwm_g_sel,
+ &pwm_g_div,
+ &pwm_g,
+ &pwm_h_sel,
+ &pwm_h_div,
+ &pwm_h,
+ &spicc_0_sel,
+ &spicc_0_div,
+ &spicc_0,
+ &spicc_1_sel,
+ &spicc_1_div,
+ &spicc_1,
+ &sd_emmc_a_sel,
+ &sd_emmc_a_div,
+ &sd_emmc_a,
+ &sd_emmc_c_sel,
+ &sd_emmc_c_div,
+ &sd_emmc_c,
+ &ts_div,
+ &ts,
+ ð_125m,
+ ð_rmii_div,
+ ð_rmii,
+ &dspa_0_sel,
+ &dspa_0_div,
+ &dspa_0,
+ &dspa_1_sel,
+ &dspa_1_div,
+ &dspa_1,
+ &dspa,
+ &nna_core_sel,
+ &nna_core_div,
+ &nna_core,
+ &nna_axi_sel,
+ &nna_axi_div,
+ &nna_axi
+};
+
+static const struct regmap_config clkc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = CLKCTRL_NNA_CLK_CNTL,
+};
+
+static struct meson_clk_hw_data a5_periphs_clks = {
+ .hws = a5_periphs_hw_clks,
+ .num = ARRAY_SIZE(a5_periphs_hw_clks),
+};
+
+static int aml_a5_peripherals_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ void __iomem *base;
+ int clkid, ret, i;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Populate regmap for the regmap backed clocks */
+ for (i = 0; i < ARRAY_SIZE(a5_periphs_clk_regmaps); i++)
+ a5_periphs_clk_regmaps[i]->map = regmap;
+
+ for (clkid = 0; clkid < a5_periphs_clks.num; clkid++) {
+ /* array might be sparse */
+ if (!a5_periphs_clks.hws[clkid])
+ continue;
+
+ ret = devm_clk_hw_register(dev, a5_periphs_clks.hws[clkid]);
+ if (ret) {
+ dev_err(dev, "Clock registration failed\n");
+ return ret;
+ }
+ }
+
+ return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
+ &a5_periphs_clks);
+}
+
+static const struct of_device_id a5_peripherals_clkc_match_table[] = {
+ {
+ .compatible = "amlogic,a5-peripherals-clkc",
+ },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, a5_peripherals_clkc_match_table);
+
+static struct platform_driver a5_peripherals_driver = {
+ .probe = aml_a5_peripherals_probe,
+ .driver = {
+ .name = "a5-peripherals-clkc",
+ .of_match_table = a5_peripherals_clkc_match_table,
+ },
+};
+module_platform_driver(a5_peripherals_driver);
+
+MODULE_DESCRIPTION("Amlogic A5 Peripherals Clock Controller driver");
+MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
+MODULE_LICENSE("GPL");
--
2.37.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller
2024-09-14 5:25 ` [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller Xianwei Zhao via B4 Relay
@ 2024-09-18 16:06 ` Rob Herring (Arm)
0 siblings, 0 replies; 17+ messages in thread
From: Rob Herring (Arm) @ 2024-09-18 16:06 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Stephen Boyd, devicetree, linux-arm-kernel, Neil Armstrong,
Kevin Hilman, Chuan Liu, linux-amlogic, Michael Turquette,
Conor Dooley, linux-clk, Jerome Brunet, Krzysztof Kozlowski,
Martin Blumenstingl, linux-kernel
On Sat, 14 Sep 2024 13:25:23 +0800, Xianwei Zhao wrote:
> From: Chuan Liu <chuan.liu@amlogic.com>
>
> Add the PLL clock controller dt-bindings for Amlogic A5 SoC family.
>
> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> .../bindings/clock/amlogic,a5-pll-clkc.yaml | 62 ++++++++++++++++++++++
> include/dt-bindings/clock/amlogic,a5-pll-clkc.h | 24 +++++++++
> 2 files changed, 86 insertions(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support
2024-09-14 5:25 ` [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support Xianwei Zhao via B4 Relay
@ 2024-09-18 16:07 ` Rob Herring (Arm)
0 siblings, 0 replies; 17+ messages in thread
From: Rob Herring (Arm) @ 2024-09-18 16:07 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Jerome Brunet, linux-clk, Neil Armstrong, Krzysztof Kozlowski,
Chuan Liu, Martin Blumenstingl, devicetree, Conor Dooley,
Kevin Hilman, linux-arm-kernel, linux-amlogic, Michael Turquette,
Stephen Boyd, linux-kernel
On Sat, 14 Sep 2024 13:25:24 +0800, Xianwei Zhao wrote:
> From: Chuan Liu <chuan.liu@amlogic.com>
>
> Add the SCMI clock controller dt-bindings for Amlogic A5 SoC family.
>
> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> include/dt-bindings/clock/amlogic,a5-scmi-clkc.h | 37 ++++++++++++++++++++++++
> 1 file changed, 37 insertions(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller
2024-09-14 5:25 ` [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller Xianwei Zhao via B4 Relay
@ 2024-09-18 16:13 ` Rob Herring (Arm)
0 siblings, 0 replies; 17+ messages in thread
From: Rob Herring (Arm) @ 2024-09-18 16:13 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Krzysztof Kozlowski, linux-clk, Conor Dooley, Kevin Hilman,
linux-amlogic, Martin Blumenstingl, Michael Turquette,
linux-arm-kernel, linux-kernel, devicetree, Chuan Liu,
Neil Armstrong, Jerome Brunet, Stephen Boyd
On Sat, 14 Sep 2024 13:25:25 +0800, Xianwei Zhao wrote:
> From: Chuan Liu <chuan.liu@amlogic.com>
>
> Add the peripherals clock controller dt-bindings for Amlogic A5 SoC family.
>
> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> .../clock/amlogic,a5-peripherals-clkc.yaml | 126 +++++++++++++++++++
> .../clock/amlogic,a5-peripherals-clkc.h | 139 +++++++++++++++++++++
> 2 files changed, 265 insertions(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock
2024-09-14 5:25 ` [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock Xianwei Zhao via B4 Relay
@ 2024-09-24 14:45 ` Jerome Brunet
2024-09-29 8:17 ` Xianwei Zhao
0 siblings, 1 reply; 17+ messages in thread
From: Jerome Brunet @ 2024-09-24 14:45 UTC (permalink / raw)
To: Xianwei Zhao via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chuan Liu, Kevin Hilman,
Martin Blumenstingl, xianwei.zhao, linux-amlogic, linux-clk,
devicetree, linux-kernel, linux-arm-kernel
On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
> From: Chuan Liu <chuan.liu@amlogic.com>
>
> Add the PLL clock controller driver for the Amlogic A5 SoC family.
>
> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> drivers/clk/meson/Kconfig | 14 ++
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a5-pll.c | 553 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 568 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 78f648c9c97d..2a713276e46c 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -132,6 +132,20 @@ config COMMON_CLK_A1_PERIPHERALS
> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
> controller to work.
>
> +config COMMON_CLK_A5_PLL
> + tristate "Amlogic A5 PLL clock controller"
> + depends on ARM64
> + default y
> + imply ARM_SCMI_PROTOCOL
don't think this is needed, same as c3
> + imply COMMON_CLK_SCMI
> + select COMMON_CLK_MESON_REGMAP
> + select COMMON_CLK_MESON_PLL
> + select COMMON_CLK_MESON_CLKC_UTILS
> + help
> + Support for the PLL clock controller on Amlogic AV40x device, AKA A5.
> + Say Y if you want the board to work, because PLLs are the parent
> + of most peripherals.
> +
> config COMMON_CLK_C3_PLL
> tristate "Amlogic C3 PLL clock controller"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index bc56a47931c1..fc4b8a723145 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a5-pll.c b/drivers/clk/meson/a5-pll.c
> new file mode 100644
> index 000000000000..d96ed72ef8d4
> --- /dev/null
> +++ b/drivers/clk/meson/a5-pll.c
> @@ -0,0 +1,553 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Amlogic A5 PLL Controller Driver
> + *
> + * Copyright (c) 2024 Amlogic, inc.
> + * Author: Chuan Liu <chuan.liu@amlogic.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-pll.h"
> +#include "clk-mpll.h"
Kconfig does not select support for this, so something is odd.
> +#include "meson-clkc-utils.h"
> +#include <dt-bindings/clock/amlogic,a5-pll-clkc.h>
> +
> +#define ANACTRL_FIXPLL_CTRL1 0x44
> +#define ANACTRL_GP0PLL_CTRL0 0x80
> +#define ANACTRL_GP0PLL_CTRL1 0x84
> +#define ANACTRL_GP0PLL_CTRL2 0x88
> +#define ANACTRL_GP0PLL_CTRL3 0x8c
> +#define ANACTRL_GP0PLL_CTRL4 0x90
> +#define ANACTRL_GP0PLL_CTRL5 0x94
> +#define ANACTRL_GP0PLL_CTRL6 0x98
> +#define ANACTRL_HIFIPLL_CTRL0 0x100
> +#define ANACTRL_HIFIPLL_CTRL1 0x104
> +#define ANACTRL_HIFIPLL_CTRL2 0x108
> +#define ANACTRL_HIFIPLL_CTRL3 0x10c
> +#define ANACTRL_HIFIPLL_CTRL4 0x110
> +#define ANACTRL_HIFIPLL_CTRL5 0x114
> +#define ANACTRL_HIFIPLL_CTRL6 0x118
> +#define ANACTRL_MPLL_CTRL0 0x180
> +#define ANACTRL_MPLL_CTRL1 0x184
> +#define ANACTRL_MPLL_CTRL2 0x188
> +#define ANACTRL_MPLL_CTRL3 0x18c
> +#define ANACTRL_MPLL_CTRL4 0x190
> +#define ANACTRL_MPLL_CTRL5 0x194
> +#define ANACTRL_MPLL_CTRL6 0x198
> +#define ANACTRL_MPLL_CTRL7 0x19c
> +#define ANACTRL_MPLL_CTRL8 0x1a0
> +
> +static DEFINE_SPINLOCK(aml_clk_lock);
Re-submit you lock patch first and adjust please.
> +
> +static struct clk_fixed_factor mpll_prediv = {
> + .mult = 1,
> + .div = 2,
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll_prediv",
> + .ops = &clk_fixed_factor_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "fix_dco"
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static const struct reg_sequence mpll0_init_regs[] = {
> + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 },
> +};
> +
> +static struct clk_regmap mpll0_div = {
> + .data = &(struct meson_clk_mpll_data){
> + .sdm = {
> + .reg_off = ANACTRL_MPLL_CTRL1,
> + .shift = 0,
> + .width = 14,
> + },
> + .sdm_en = {
> + .reg_off = ANACTRL_MPLL_CTRL1,
> + .shift = 30,
> + .width = 1,
> + },
> + .n2 = {
> + .reg_off = ANACTRL_MPLL_CTRL1,
> + .shift = 20,
> + .width = 9,
> + },
> + .ssen = {
> + .reg_off = ANACTRL_MPLL_CTRL1,
> + .shift = 29,
> + .width = 1,
> + },
> + .lock = &aml_clk_lock,
> + .init_regs = mpll0_init_regs,
> + .init_count = ARRAY_SIZE(mpll0_init_regs),
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll0_div",
> + .ops = &meson_clk_mpll_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &mpll_prediv.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap mpll0 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = ANACTRL_MPLL_CTRL1,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll0",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) { &mpll0_div.hw },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct reg_sequence mpll1_init_regs[] = {
> + { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 },
> +};
> +
> +static struct clk_regmap mpll1_div = {
> + .data = &(struct meson_clk_mpll_data){
> + .sdm = {
> + .reg_off = ANACTRL_MPLL_CTRL3,
> + .shift = 0,
> + .width = 14,
> + },
> + .sdm_en = {
> + .reg_off = ANACTRL_MPLL_CTRL3,
> + .shift = 30,
> + .width = 1,
> + },
> + .n2 = {
> + .reg_off = ANACTRL_MPLL_CTRL3,
> + .shift = 20,
> + .width = 9,
> + },
> + .ssen = {
> + .reg_off = ANACTRL_MPLL_CTRL3,
> + .shift = 29,
> + .width = 1,
> + },
> + .lock = &aml_clk_lock,
> + .init_regs = mpll1_init_regs,
> + .init_count = ARRAY_SIZE(mpll1_init_regs),
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll1_div",
> + .ops = &meson_clk_mpll_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &mpll_prediv.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap mpll1 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = ANACTRL_MPLL_CTRL3,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll1",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) { &mpll1_div.hw },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct reg_sequence mpll2_init_regs[] = {
> + { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 },
> +};
> +
> +static struct clk_regmap mpll2_div = {
> + .data = &(struct meson_clk_mpll_data){
> + .sdm = {
> + .reg_off = ANACTRL_MPLL_CTRL5,
> + .shift = 0,
> + .width = 14,
> + },
> + .sdm_en = {
> + .reg_off = ANACTRL_MPLL_CTRL5,
> + .shift = 30,
> + .width = 1,
> + },
> + .n2 = {
> + .reg_off = ANACTRL_MPLL_CTRL5,
> + .shift = 20,
> + .width = 9,
> + },
> + .ssen = {
> + .reg_off = ANACTRL_MPLL_CTRL5,
> + .shift = 29,
> + .width = 1,
> + },
> + .lock = &aml_clk_lock,
> + .init_regs = mpll2_init_regs,
> + .init_count = ARRAY_SIZE(mpll2_init_regs),
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll2_div",
> + .ops = &meson_clk_mpll_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &mpll_prediv.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap mpll2 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = ANACTRL_MPLL_CTRL5,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll2",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) { &mpll2_div.hw },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct reg_sequence mpll3_init_regs[] = {
> + { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 },
> +};
> +
> +static struct clk_regmap mpll3_div = {
> + .data = &(struct meson_clk_mpll_data){
> + .sdm = {
> + .reg_off = ANACTRL_MPLL_CTRL7,
> + .shift = 0,
> + .width = 14,
> + },
> + .sdm_en = {
> + .reg_off = ANACTRL_MPLL_CTRL7,
> + .shift = 30,
> + .width = 1,
> + },
> + .n2 = {
> + .reg_off = ANACTRL_MPLL_CTRL7,
> + .shift = 20,
> + .width = 9,
> + },
> + .ssen = {
> + .reg_off = ANACTRL_MPLL_CTRL7,
> + .shift = 29,
> + .width = 1,
> + },
> + .lock = &aml_clk_lock,
> + .init_regs = mpll3_init_regs,
> + .init_count = ARRAY_SIZE(mpll3_init_regs),
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll3_div",
> + .ops = &meson_clk_mpll_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &mpll_prediv.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap mpll3 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = ANACTRL_MPLL_CTRL7,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "mpll3",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) { &mpll3_div.hw },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct reg_sequence gp0_init_regs[] = {
> + { .reg = ANACTRL_GP0PLL_CTRL0, .def = 0X08000000 },
> + { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 },
> + { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 },
> + { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x6a295c00 },
> + { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x65771290 },
> + { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a },
> + { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x54540000 }
> +};
> +
> +static const struct pll_mult_range gp0_pll_mult_range = {
> + .min = 125,
> + .max = 250,
> +};
> +
> +static struct clk_regmap gp0_pll_dco = {
> + .data = &(struct meson_clk_pll_data) {
> + .en = {
> + .reg_off = ANACTRL_GP0PLL_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .m = {
> + .reg_off = ANACTRL_GP0PLL_CTRL0,
> + .shift = 0,
> + .width = 8,
> + },
> + .frac = {
> + .reg_off = ANACTRL_GP0PLL_CTRL1,
> + .shift = 0,
> + .width = 17,
> + },
> + .n = {
> + .reg_off = ANACTRL_GP0PLL_CTRL0,
> + .shift = 10,
> + .width = 5,
> + },
> + .l = {
> + .reg_off = ANACTRL_GP0PLL_CTRL0,
> + .shift = 31,
> + .width = 1,
> + },
> + .rst = {
> + .reg_off = ANACTRL_GP0PLL_CTRL0,
> + .shift = 29,
> + .width = 1,
> + },
> + .range = &gp0_pll_mult_range,
> + .init_regs = gp0_init_regs,
> + .init_count = ARRAY_SIZE(gp0_init_regs),
> + .frac_max = 100000,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "gp0_pll_dco",
> + .ops = &meson_clk_pll_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal_24m",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +/* The maximum frequency divider supports is 16, not 128(2^7) */
> +static const struct clk_div_table gp0_pll_od_table[] = {
> + { 0, 1 },
> + { 1, 2 },
> + { 2, 4 },
> + { 3, 8 },
> + { 4, 16 },
> + { 5, 32 },
> + { /* sentinel */ }
> +};
> +
> +static struct clk_regmap gp0_pll = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = ANACTRL_GP0PLL_CTRL0,
> + .shift = 16,
> + .width = 3,
> + .table = gp0_pll_od_table,
> + .flags = CLK_DIVIDER_POWER_OF_TWO,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "gp0_pll",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &gp0_pll_dco.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct reg_sequence hifi_init_regs[] = {
> + { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0X08000000 },
What is bit you are flipping in CTRL0 ? it is suspicious
> + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00000000 },
> + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
> + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a295c00 },
> + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
> + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
> + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x54540000 }
> +};
> +
> +static const struct pll_mult_range hifi_pll_mult_range = {
> + .min = 125,
> + .max = 250,
> +};
> +
> +static struct clk_regmap hifi_pll_dco = {
> + .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,
> + },
> + .frac = {
> + .reg_off = ANACTRL_HIFIPLL_CTRL1,
> + .shift = 0,
> + .width = 17,
> + },
> + .n = {
> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
> + .shift = 10,
> + .width = 5,
> + },
> + .l = {
> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
> + .shift = 31,
> + .width = 1,
> + },
> + .rst = {
> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
> + .shift = 29,
> + .width = 1,
> + },
> + .range = &hifi_pll_mult_range,
> + .init_regs = hifi_init_regs,
> + .init_count = ARRAY_SIZE(hifi_init_regs),
> + .frac_max = 100000,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "hifi_pll_dco",
> + .ops = &meson_clk_pll_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal_24m",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +/* The maximum frequency divider supports is 16, not 128(2^7) */
> +static const struct clk_div_table hifi_pll_od_table[] = {
> + { 0, 1 },
> + { 1, 2 },
> + { 2, 4 },
> + { 3, 8 },
Why don't you ajust the mask then ? Looks like a POW_OF_2 basic
dividider to me.
> + { /* sentinel */ }
> +};
> +
> +static struct clk_regmap hifi_pll = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = ANACTRL_HIFIPLL_CTRL0,
> + .shift = 16,
> + .width = 3,
> + .table = hifi_pll_od_table,
> + .flags = CLK_DIVIDER_POWER_OF_TWO,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "hifi_pll",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &hifi_pll_dco.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_hw *a5_pll_hw_clks[] = {
> + [CLKID_MPLL_PREDIV] = &mpll_prediv.hw,
> + [CLKID_MPLL0_DIV] = &mpll0_div.hw,
> + [CLKID_MPLL0] = &mpll0.hw,
> + [CLKID_MPLL1_DIV] = &mpll1_div.hw,
> + [CLKID_MPLL1] = &mpll1.hw,
> + [CLKID_MPLL2_DIV] = &mpll2_div.hw,
> + [CLKID_MPLL2] = &mpll2.hw,
> + [CLKID_MPLL3_DIV] = &mpll3_div.hw,
> + [CLKID_MPLL3] = &mpll3.hw,
> + [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw,
> + [CLKID_GP0_PLL] = &gp0_pll.hw,
> + [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw,
> + [CLKID_HIFI_PLL] = &hifi_pll.hw
> +};
> +
> +/* Convenience table to populate regmap in .probe */
> +static struct clk_regmap *const a5_pll_clk_regmaps[] = {
> + &mpll0_div,
> + &mpll0,
> + &mpll1_div,
> + &mpll1,
> + &mpll2_div,
> + &mpll2,
> + &mpll3_div,
> + &mpll3,
> + &gp0_pll_dco,
> + &gp0_pll,
> + &hifi_pll_dco,
> + &hifi_pll
> +};
> +
> +static const struct regmap_config clkc_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = ANACTRL_MPLL_CTRL8,
> +};
> +
> +static struct meson_clk_hw_data a5_pll_clks = {
> + .hws = a5_pll_hw_clks,
> + .num = ARRAY_SIZE(a5_pll_hw_clks),
> +};
> +
> +static int aml_a5_pll_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct regmap *regmap;
> + void __iomem *base;
> + int clkid, ret, i;
> +
> + base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + /* Populate regmap for the regmap backed clocks */
> + for (i = 0; i < ARRAY_SIZE(a5_pll_clk_regmaps); i++)
> + a5_pll_clk_regmaps[i]->map = regmap;
> +
> + for (clkid = 0; clkid < a5_pll_clks.num; clkid++) {
> + /* array might be sparse */
> + if (!a5_pll_clks.hws[clkid])
> + continue;
> +
> + ret = devm_clk_hw_register(dev, a5_pll_clks.hws[clkid]);
> + if (ret) {
> + dev_err(dev, "Clock registration failed\n");
> + return ret;
> + }
> + }
> +
> + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
> + &a5_pll_clks);
> +}
> +
> +static const struct of_device_id a5_pll_clkc_match_table[] = {
> + {
> + .compatible = "amlogic,a5-pll-clkc",
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, a5_pll_clkc_match_table);
> +
> +static struct platform_driver a5_pll_driver = {
> + .probe = aml_a5_pll_probe,
> + .driver = {
> + .name = "a5-pll-clkc",
> + .of_match_table = a5_pll_clkc_match_table,
> + },
> +};
> +module_platform_driver(a5_pll_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A5 PLL Clock Controller driver");
> +MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
> +MODULE_LICENSE("GPL");
--
Jerome
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver
2024-09-14 5:25 ` [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver Xianwei Zhao via B4 Relay
@ 2024-09-24 15:09 ` Jerome Brunet
2024-09-29 8:44 ` Xianwei Zhao
0 siblings, 1 reply; 17+ messages in thread
From: Jerome Brunet @ 2024-09-24 15:09 UTC (permalink / raw)
To: Xianwei Zhao via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chuan Liu, Kevin Hilman,
Martin Blumenstingl, xianwei.zhao, linux-amlogic, linux-clk,
devicetree, linux-kernel, linux-arm-kernel
On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
> From: Chuan Liu <chuan.liu@amlogic.com>
>
> Add the peripherals clock controller driver in the A5 SoC family.
>
> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
> ---
> drivers/clk/meson/Kconfig | 14 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a5-peripherals.c | 1471 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1486 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 2a713276e46c..21845edcd8ef 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -146,6 +146,20 @@ config COMMON_CLK_A5_PLL
> Say Y if you want the board to work, because PLLs are the parent
> of most peripherals.
>
> +config COMMON_CLK_A5_PERIPHERALS
> + tristate "Amlogic A5 peripherals clock controller"
> + depends on ARM64
> + default y
> + imply ARM_SCMI_PROTOCOL
same
> + imply COMMON_CLK_SCMI
> + imply COMMON_CLK_A5_PLL
> + select COMMON_CLK_MESON_REGMAP
> + select COMMON_CLK_MESON_DUALDIV
> + select COMMON_CLK_MESON_CLKC_UTILS
> + help
> + Support for the Peripherals clock controller on Amlogic AV40x device,
> + AKA A5. Say Y if you want the peripherals clock to work.
> +
> config COMMON_CLK_C3_PLL
> tristate "Amlogic C3 PLL clock controller"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index fc4b8a723145..58236c6e8377 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
> +obj-$(CONFIG_COMMON_CLK_A5_PERIPHERALS) += a5-peripherals.o
> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a5-peripherals.c b/drivers/clk/meson/a5-peripherals.c
> new file mode 100644
> index 000000000000..c28da340a5af
> --- /dev/null
> +++ b/drivers/clk/meson/a5-peripherals.c
> @@ -0,0 +1,1471 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Amlogic A5 Peripherals Clock Controller Driver
> + *
> + * Copyright (c) 2024 Amlogic, inc.
> + * Author: Chuan Liu <chuan.liu@amlogic.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +#include <dt-bindings/clock/amlogic,a5-peripherals-clkc.h>
> +
> +#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x8
> +#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0xc
> +#define CLKCTRL_RTC_CTRL 0x10
> +#define CLKCTRL_SYS_CLK_EN0_REG0 0x44
> +#define CLKCTRL_SYS_CLK_EN0_REG1 0x48
> +#define CLKCTRL_DSPA_CLK_CTRL0 0x9c
> +#define CLKCTRL_CLK12_24_CTRL 0xa8
> +#define CLKCTRL_AXI_CLK_EN0 0xac
> +#define CLKCTRL_TS_CLK_CTRL 0x158
> +#define CLKCTRL_ETH_CLK_CTRL 0x164
> +#define CLKCTRL_NAND_CLK_CTRL 0x168
> +#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c
> +#define CLKCTRL_SPICC_CLK_CTRL 0x174
> +#define CLKCTRL_GEN_CLK_CTRL 0x178
> +#define CLKCTRL_SAR_CLK_CTRL0 0x17c
> +#define CLKCTRL_PWM_CLK_AB_CTRL 0x180
> +#define CLKCTRL_PWM_CLK_CD_CTRL 0x184
> +#define CLKCTRL_PWM_CLK_EF_CTRL 0x188
> +#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c
> +#define CLKCTRL_NNA_CLK_CNTL 0x220
Again I see a lot of holes in there. Please make sure there is only
clocks in the whole region you are claiming for the device.
Otherwise it is fine to register as many controller as necessary
> +
> +static struct clk_regmap rtc_xtal_clkin = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_xtal_clkin",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "oscin",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static const struct meson_clk_dualdiv_param rtc_32k_div_table[] = {
> + { 733, 732, 8, 11, 1 },
> + { /* sentinel */ }
> +};
> +
> +static struct clk_regmap rtc_32k_div = {
> + .data = &(struct meson_clk_dualdiv_data) {
> + .n1 = {
> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
> + .shift = 0,
> + .width = 12,
> + },
> + .n2 = {
> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
> + .shift = 12,
> + .width = 12,
> + },
> + .m1 = {
> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
> + .shift = 0,
> + .width = 12,
> + },
> + .m2 = {
> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
> + .shift = 12,
> + .width = 12,
> + },
> + .dual = {
> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .table = rtc_32k_div_table,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_32k_div",
> + .ops = &meson_clk_dualdiv_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_xtal_clkin.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static const struct clk_parent_data rtc_32k_mux_parent_data[] = {
> + { .hw = &rtc_32k_div.hw },
> + { .hw = &rtc_xtal_clkin.hw }
> +};
> +
> +static struct clk_regmap rtc_32k_mux = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL1,
> + .mask = 0x1,
> + .shift = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_32k_mux",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = rtc_32k_mux_parent_data,
> + .num_parents = ARRAY_SIZE(rtc_32k_mux_parent_data),
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap rtc_32k = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
> + .bit_idx = 30,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_32k",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_32k_mux.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data rtc_clk_mux_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .hw = &rtc_32k.hw },
> + { .fw_name = "pad_osc" }
> +};
> +
> +static struct clk_regmap rtc_clk = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_RTC_CTRL,
> + .mask = 0x3,
> + .shift = 0,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_clk",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = rtc_clk_mux_parent_data,
> + .num_parents = ARRAY_SIZE(rtc_clk_mux_parent_data),
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +#define A4_CLK_GATE(_name, _reg, _bit, _fw_name, _ops, _flags)
> \
A4 ??? everything else is A5 ? Please explain
> +struct clk_regmap _name = { \
> + .data = &(struct clk_regmap_gate_data){ \
> + .offset = (_reg), \
> + .bit_idx = (_bit), \
> + }, \
> + .hw.init = &(struct clk_init_data) { \
> + .name = #_name, \
> + .ops = _ops, \
> + .parent_data = &(const struct clk_parent_data) { \
> + .fw_name = #_fw_name, \
> + }, \
> + .num_parents = 1, \
> + .flags = (_flags), \
> + }, \
> +}
> +
> +#define A4_SYS_GATE(_name, _reg, _bit, _flags) \
> + A4_CLK_GATE(_name, _reg, _bit, sysclk, \
> + &clk_regmap_gate_ops, _flags)
> +
> +#define A4_SYS_GATE_RO(_name, _reg, _bit) \
> + A4_CLK_GATE(_name, _reg, _bit, sysclk, \
> + &clk_regmap_gate_ro_ops, 0)
Looks like a copy/paste of the C3. If this pattern keeps on repeating,
it would be nice to make a common definition
> +
> +static A4_SYS_GATE(sys_reset_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 1, 0);
> +static A4_SYS_GATE(sys_pwr_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 3, 0);
> +static A4_SYS_GATE(sys_pad_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 4, 0);
> +static A4_SYS_GATE(sys_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 5, 0);
> +static A4_SYS_GATE(sys_ts_pll, CLKCTRL_SYS_CLK_EN0_REG0, 6, 0);
> +
> +/*
> + * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that
> + * access the AXI bus.
> + */
> +static A4_SYS_GATE(sys_dev_arb, CLKCTRL_SYS_CLK_EN0_REG0, 7, 0);
> +
> +/*
> + * FIXME: sys_mmc_pclk provides the clock for the DDR PHY, DDR will only be
> + * initialized in bl2, and this clock should not be touched in linux.
> + */
> +static A4_SYS_GATE_RO(sys_mmc_pclk, CLKCTRL_SYS_CLK_EN0_REG0, 8);
> +static A4_SYS_GATE(sys_mailbox, CLKCTRL_SYS_CLK_EN0_REG0, 10, 0);
> +
> +/*
> + * NOTE: sys_cpu_ctrl provides the clock for CPU controller. After clock is
> + * disabled, cpu_clk and other key CPU-related configurations cannot take effect.
> + */
> +static A4_SYS_GATE(sys_cpu_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL);
> +static A4_SYS_GATE(sys_jtag_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 12, 0);
> +static A4_SYS_GATE(sys_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 13, 0);
> +
> +/*
> + * NOTE: sys_irq_ctrl provides the clock for IRQ controller. The IRQ controller
> + * collects and distributes the interrupt signal to the GIC, PWR_CTRL, and
> + * AOCPU. If the clock is disabled, interrupt-related functions will occurs an
> + * exception.
> + */
> +static A4_SYS_GATE(sys_irq_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL);
> +static A4_SYS_GATE(sys_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 15, 0);
> +static A4_SYS_GATE(sys_rom, CLKCTRL_SYS_CLK_EN0_REG0, 16, 0);
> +static A4_SYS_GATE(sys_cpu_apb, CLKCTRL_SYS_CLK_EN0_REG0, 18, 0);
> +static A4_SYS_GATE(sys_rsa, CLKCTRL_SYS_CLK_EN0_REG0, 19, 0);
> +static A4_SYS_GATE(sys_sar_adc, CLKCTRL_SYS_CLK_EN0_REG0, 20, 0);
> +static A4_SYS_GATE(sys_startup, CLKCTRL_SYS_CLK_EN0_REG0, 21, 0);
> +static A4_SYS_GATE(sys_secure, CLKCTRL_SYS_CLK_EN0_REG0, 22, 0);
> +static A4_SYS_GATE(sys_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 23, 0);
> +static A4_SYS_GATE(sys_dspa, CLKCTRL_SYS_CLK_EN0_REG0, 24, 0);
> +static A4_SYS_GATE(sys_nna, CLKCTRL_SYS_CLK_EN0_REG0, 25, 0);
> +static A4_SYS_GATE(sys_eth_mac, CLKCTRL_SYS_CLK_EN0_REG0, 26, 0);
> +
> +/*
> + * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller).
> + * After clock is disabled, The GIC cannot work properly. At present, the driver
> + * used by our GIC is the public driver in kernel, and there is no management
> + * clock in the driver.
> + */
> +static A4_SYS_GATE(sys_gic, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL);
The GIC has a driver. If it needs clock, maybe it should request it and
enable it, maybe as optional.
> +static A4_SYS_GATE(sys_rama, CLKCTRL_SYS_CLK_EN0_REG0, 28, 0);
> +
> +/*
> + * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network
> + * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC,
> + * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the
> + * system. After clock is disabled, The NIC cannot work.
> + */
This comment looks like a clock that should be passed as ressource to a
bus or power-domain to be properly manage. This is a pattern that keeps
on repeating. I will not block you on it this time around but I strong
suggest you fix up the situation on the related platform. Next time
around, the reason won't be a valid one.
> +static A4_SYS_GATE(sys_big_nic, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL);
> +static A4_SYS_GATE(sys_ramb, CLKCTRL_SYS_CLK_EN0_REG0, 30, 0);
> +static A4_SYS_GATE(sys_audio_top, CLKCTRL_SYS_CLK_EN0_REG1, 0, 0);
> +static A4_SYS_GATE(sys_audio_vad, CLKCTRL_SYS_CLK_EN0_REG1, 1, 0);
> +static A4_SYS_GATE(sys_usb, CLKCTRL_SYS_CLK_EN0_REG1, 2, 0);
> +static A4_SYS_GATE(sys_sd_emmc_a, CLKCTRL_SYS_CLK_EN0_REG1, 3, 0);
> +static A4_SYS_GATE(sys_sd_emmc_c, CLKCTRL_SYS_CLK_EN0_REG1, 4, 0);
> +static A4_SYS_GATE(sys_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG1, 5, 0);
> +static A4_SYS_GATE(sys_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG1, 6, 0);
> +static A4_SYS_GATE(sys_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG1, 7, 0);
> +static A4_SYS_GATE(sys_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG1, 8, 0);
> +static A4_SYS_GATE(sys_spicc_1, CLKCTRL_SYS_CLK_EN0_REG1, 9, 0);
> +static A4_SYS_GATE(sys_spicc_0, CLKCTRL_SYS_CLK_EN0_REG1, 10, 0);
> +static A4_SYS_GATE(sys_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 11, 0);
> +static A4_SYS_GATE(sys_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 12, 0);
> +static A4_SYS_GATE(sys_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 13, 0);
> +static A4_SYS_GATE(sys_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 14, 0);
> +static A4_SYS_GATE(sys_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 15, 0);
> +static A4_SYS_GATE(sys_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 16, 0);
> +static A4_SYS_GATE(sys_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 17, 0);
> +static A4_SYS_GATE(sys_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG1, 18, 0);
> +static A4_SYS_GATE(sys_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG1, 19, 0);
> +static A4_SYS_GATE(sys_rtc, CLKCTRL_SYS_CLK_EN0_REG1, 21, 0);
> +
> +#define A4_AXI_GATE(_name, _reg, _bit, _flags) \
> + A4_CLK_GATE(_name, _reg, _bit, axiclk, \
> + &clk_regmap_gate_ops, _flags)
> +
> +static A4_AXI_GATE(axi_audio_vad, CLKCTRL_AXI_CLK_EN0, 0, 0);
> +static A4_AXI_GATE(axi_audio_top, CLKCTRL_AXI_CLK_EN0, 1, 0);
> +
> +/*
> + * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After
> + * clock is disabled, The NIC cannot work.
> + */
> +static A4_AXI_GATE(axi_sys_nic, CLKCTRL_AXI_CLK_EN0, 2, CLK_IS_CRITICAL);
> +static A4_AXI_GATE(axi_ramb, CLKCTRL_AXI_CLK_EN0, 5, 0);
> +static A4_AXI_GATE(axi_rama, CLKCTRL_AXI_CLK_EN0, 6, 0);
> +
> +/*
> + * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses
> + * the DDR. After clock is disabled, The CPU will not have access to the DDR.
> + */
> +static A4_AXI_GATE(axi_cpu_dmc, CLKCTRL_AXI_CLK_EN0, 7, CLK_IS_CRITICAL);
> +static A4_AXI_GATE(axi_nna, CLKCTRL_AXI_CLK_EN0, 12, 0);
> +
> +/*
> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
> + */
Same.
> +static A4_AXI_GATE(axi_dev1_dmc, CLKCTRL_AXI_CLK_EN0, 13, 0);
> +
> +/*
> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
> + * to access the AXI bus of the DDR.
> + */
> +static A4_AXI_GATE(axi_dev0_dmc, CLKCTRL_AXI_CLK_EN0, 14, 0);
> +static A4_AXI_GATE(axi_dsp_dmc, CLKCTRL_AXI_CLK_EN0, 15, 0);
> +
> +static struct clk_regmap clk_12_24m_in = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_CLK12_24_CTRL,
> + .bit_idx = 11,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "clk_12_24m_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal_24m",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap clk_12_24m = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_CLK12_24_CTRL,
> + .shift = 10,
> + .width = 1,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "clk_12_24m",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &clk_12_24m_in.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +/* FIXME: set value 0 will div by 2 like value 1 */
Again, it is fine when it happens once, like the c3.
When the pattern starts repeating, it is time to do something about it.
> +static struct clk_regmap fclk_25m_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_CLK12_24_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "fclk_25m_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "fix",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap fclk_25m = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_CLK12_24_CTRL,
> + .bit_idx = 12,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "fclk_25m",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &fclk_25m_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +/*
> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk)
> + * is manged by clock measures module. Their hardware are out of clock tree.
Yet, they exist and should be part of the bindings since they are
obviously input to this clock.
> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
> + *
> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug purposes.
> + */
> +static u32 gen_parent_table[] = { 0, 1, 2, 6, 7, 17, 19, 20, 21, 22, 23, 24, 25,
> + 26, 27, 28};
> +
> +static const struct clk_parent_data gen_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .hw = &rtc_clk.hw },
> + { .fw_name = "sysplldiv16" },
> + { .fw_name = "gp1" },
> + { .fw_name = "hifi" },
> + { .fw_name = "cpudiv16" },
> + { .fw_name = "fdiv2" },
> + { .fw_name = "fdiv2p5" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "fdiv4" },
> + { .fw_name = "fdiv5" },
> + { .fw_name = "fdiv7" },
> + { .fw_name = "mpll0" },
> + { .fw_name = "mpll1" },
> + { .fw_name = "mpll2" },
> + { .fw_name = "mpll3" }
> +};
> +
> +static struct clk_regmap gen_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_GEN_CLK_CTRL,
> + .mask = 0x1f,
> + .shift = 12,
> + .table = gen_parent_table,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "gen_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = gen_parent_data,
> + .num_parents = ARRAY_SIZE(gen_parent_data),
> + },
> +};
> +
> +static struct clk_regmap gen_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_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 *[]) {
> + &gen_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap gen = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_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 *[]) {
> + &gen_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data saradc_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .fw_name = "sysclk" }
> +};
> +
> +static struct clk_regmap saradc_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_SAR_CLK_CTRL0,
> + .mask = 0x1,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "saradc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = saradc_parent_data,
> + .num_parents = ARRAY_SIZE(saradc_parent_data),
> + },
> +};
> +
> +static struct clk_regmap saradc_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_SAR_CLK_CTRL0,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "saradc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &saradc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap saradc = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_SAR_CLK_CTRL0,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "saradc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &saradc_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data pwm_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .hw = &rtc_clk.hw },
> + { .fw_name = "fdiv4" },
> + { .fw_name = "fdiv3" }
> +};
> +
> +#define AML_PWM_CLK_MUX(_name, _reg, _shift) { \
> + .data = &(struct clk_regmap_mux_data) { \
> + .offset = _reg, \
> + .mask = 0x3, \
> + .shift = _shift, \
> + }, \
> + .hw.init = &(struct clk_init_data) { \
> + .name = #_name "_sel", \
> + .ops = &clk_regmap_mux_ops, \
> + .parent_data = pwm_parent_data, \
> + .num_parents = ARRAY_SIZE(pwm_parent_data), \
> + }, \
> +}
> +
> +#define AML_PWM_CLK_DIV(_name, _reg, _shift) { \
> + .data = &(struct clk_regmap_div_data) { \
> + .offset = _reg, \
> + .shift = _shift, \
> + .width = 8, \
> + }, \
> + .hw.init = &(struct clk_init_data) { \
> + .name = #_name "_div", \
> + .ops = &clk_regmap_divider_ops, \
> + .parent_names = (const char *[]) { #_name "_sel" },\
> + .num_parents = 1, \
> + .flags = CLK_SET_RATE_PARENT, \
> + }, \
> +}
> +
> +#define AML_PWM_CLK_GATE(_name, _reg, _bit) { \
> + .data = &(struct clk_regmap_gate_data) { \
> + .offset = _reg, \
> + .bit_idx = _bit, \
> + }, \
> + .hw.init = &(struct clk_init_data) { \
> + .name = #_name, \
> + .ops = &clk_regmap_gate_ops, \
> + .parent_names = (const char *[]) { #_name "_div" },\
> + .num_parents = 1, \
> + .flags = CLK_SET_RATE_PARENT, \
> + }, \
> +}
Now the prefix is just AML ? please be consistent
And again, looks like a repeating pattern of these families you've been
upstreaming lately.
> +
> +static struct clk_regmap pwm_a_sel =
> + AML_PWM_CLK_MUX(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 9);
> +static struct clk_regmap pwm_a_div =
> + AML_PWM_CLK_DIV(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 0);
> +static struct clk_regmap pwm_a =
> + AML_PWM_CLK_GATE(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 8);
> +
> +static struct clk_regmap pwm_b_sel =
> + AML_PWM_CLK_MUX(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 25);
> +static struct clk_regmap pwm_b_div =
> + AML_PWM_CLK_DIV(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 16);
> +static struct clk_regmap pwm_b =
> + AML_PWM_CLK_GATE(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 24);
> +
> +static struct clk_regmap pwm_c_sel =
> + AML_PWM_CLK_MUX(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 9);
> +static struct clk_regmap pwm_c_div =
> + AML_PWM_CLK_DIV(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 0);
> +static struct clk_regmap pwm_c =
> + AML_PWM_CLK_GATE(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 8);
> +
> +static struct clk_regmap pwm_d_sel =
> + AML_PWM_CLK_MUX(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 25);
> +static struct clk_regmap pwm_d_div =
> + AML_PWM_CLK_DIV(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 16);
> +static struct clk_regmap pwm_d =
> + AML_PWM_CLK_GATE(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 24);
> +
> +static struct clk_regmap pwm_e_sel =
> + AML_PWM_CLK_MUX(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 9);
> +static struct clk_regmap pwm_e_div =
> + AML_PWM_CLK_DIV(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 0);
> +static struct clk_regmap pwm_e =
> + AML_PWM_CLK_GATE(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 8);
> +
> +static struct clk_regmap pwm_f_sel =
> + AML_PWM_CLK_MUX(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 25);
> +static struct clk_regmap pwm_f_div =
> + AML_PWM_CLK_DIV(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 16);
> +static struct clk_regmap pwm_f =
> + AML_PWM_CLK_GATE(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 24);
> +
> +static struct clk_regmap pwm_g_sel =
> + AML_PWM_CLK_MUX(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 9);
> +static struct clk_regmap pwm_g_div =
> + AML_PWM_CLK_DIV(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 0);
> +static struct clk_regmap pwm_g =
> + AML_PWM_CLK_GATE(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 8);
> +
> +static struct clk_regmap pwm_h_sel =
> + AML_PWM_CLK_MUX(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25);
> +static struct clk_regmap pwm_h_div =
> + AML_PWM_CLK_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16);
> +static struct clk_regmap pwm_h =
> + AML_PWM_CLK_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24);
> +
> +/* Channel 7 is gp1. */
and ? if GP1 is RO, why can't you add it here ?
> +static const struct clk_parent_data spicc_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .fw_name = "sysclk" },
> + { .fw_name = "fdiv4" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "fdiv2" },
> + { .fw_name = "fdiv5" },
> + { .fw_name = "fdiv7" }
> +};
> +
> +static struct clk_regmap spicc_0_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_0_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = spicc_parent_data,
> + .num_parents = ARRAY_SIZE(spicc_parent_data),
> + },
> +};
> +
> +static struct clk_regmap spicc_0_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .shift = 0,
> + .width = 6,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_0_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_0_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spicc_0 = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .bit_idx = 6,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_0",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_0_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spicc_1_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 23,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_1_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = spicc_parent_data,
> + .num_parents = ARRAY_SIZE(spicc_parent_data),
> + },
> +};
> +
> +static struct clk_regmap spicc_1_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .shift = 16,
> + .width = 6,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_1_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_1_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spicc_1 = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_SPICC_CLK_CTRL,
> + .bit_idx = 22,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc_1",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_1_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data emmc_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .fw_name = "fdiv2" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "hifi" },
> + { .fw_name = "fdiv2p5" },
> + { .fw_name = "mpll2" },
> + { .fw_name = "mpll3" },
> + { .fw_name = "gp0" }
> +};
> +
> +static struct clk_regmap sd_emmc_a_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_a_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = emmc_parent_data,
> + .num_parents = ARRAY_SIZE(emmc_parent_data),
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_a_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
> + .shift = 0,
> + .width = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_a_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_a_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_a = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
> + .bit_idx = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_a",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_a_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_c_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_NAND_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_c_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = emmc_parent_data,
> + .num_parents = ARRAY_SIZE(emmc_parent_data),
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_c_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_NAND_CLK_CTRL,
> + .shift = 0,
> + .width = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_c_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_c_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_c = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_NAND_CLK_CTRL,
> + .bit_idx = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc_c",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_c_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap ts_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_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 = "oscin",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap ts = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_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 *[]) {
> + &ts_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_fixed_factor eth_125m_div = {
> + .mult = 1,
> + .div = 8,
> + .hw.init = &(struct clk_init_data) {
> + .name = "eth_125m_div",
> + .ops = &clk_fixed_factor_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "fdiv2",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap eth_125m = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_ETH_CLK_CTRL,
> + .bit_idx = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "eth_125m",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + ð_125m_div.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap eth_rmii_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_ETH_CLK_CTRL,
> + .shift = 0,
> + .width = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "eth_rmii_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "fdiv2",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap eth_rmii = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_ETH_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "eth_rmii",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + ð_rmii_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +/* Channel 6 is gp1. */
same
> +static u32 dspa_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
> +
> +static const struct clk_parent_data dspa_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .fw_name = "fdiv2p5" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "rtc" },
> + { .fw_name = "hifi" },
> + { .fw_name = "fdiv4" },
> + { .hw = &rtc_clk.hw }
> +};
> +
> +static struct clk_regmap dspa_0_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 10,
> + .table = dspa_parent_table,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_0_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dspa_parent_data,
> + .num_parents = ARRAY_SIZE(dspa_parent_data),
> + },
> +};
> +
> +static struct clk_regmap dspa_0_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .shift = 0,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_0_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_0_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_0 = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .bit_idx = 13,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_0",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_0_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_1_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 26,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_1_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dspa_parent_data,
> + .num_parents = ARRAY_SIZE(dspa_parent_data),
> + },
> +};
> +
> +static struct clk_regmap dspa_1_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .shift = 16,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_1_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_1_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_1 = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .bit_idx = 29,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_1",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_1_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
A word about SET_RATE_GATE ?
> + },
> +};
> +
> +static struct clk_regmap dspa = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_0.hw,
> + &dspa_1.hw
> + },
> + .num_parents = 2,
> + /*
> + * NOTE: This level of mux is "no glitch mux", and mux_0
> + * (here dspa_0) is not only the clock source for mux, but also
> + * provides a working clock for "no glitch mux". "no glitch mux"
> + * can be switched only when mux_0 has a clock input. Therefore,
> + * add flag CLK_OPS_PARENT_ENABLE to ensure that mux_0 has clock
> + * when "no glitch mux" works.
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
Humm CLK_OPS_PARENT_ENABLE is not how we have handling glitch free mux
so far. What changed ?
> + },
> +};
> +
> +/* Channel 6 is gp1. */
> +static u32 nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
> +
> +static const struct clk_parent_data nna_parent_data[] = {
> + { .fw_name = "oscin" },
> + { .fw_name = "fdiv2p5" },
> + { .fw_name = "fdiv4" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "fdiv5" },
> + { .fw_name = "fdiv2" },
> + { .fw_name = "hifi" }
> +};
> +
> +static struct clk_regmap nna_core_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .mask = 0x7,
> + .shift = 9,
> + .table = nna_parent_table,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_core_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = nna_parent_data,
> + .num_parents = ARRAY_SIZE(nna_parent_data),
> + },
> +};
> +
> +static struct clk_regmap nna_core_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .shift = 0,
> + .width = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_core_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &nna_core_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap nna_core = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_core",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &nna_core_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap nna_axi_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .mask = 0x7,
> + .shift = 25,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_axi_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = nna_parent_data,
> + .num_parents = ARRAY_SIZE(nna_parent_data),
> + },
> +};
> +
> +static struct clk_regmap nna_axi_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .shift = 16,
> + .width = 7,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_axi_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &nna_axi_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap nna_axi = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLKCTRL_NNA_CLK_CNTL,
> + .bit_idx = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "nna_axi",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &nna_axi_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_hw *a5_periphs_hw_clks[] = {
> + [CLKID_RTC_XTAL_CLKIN] = &rtc_xtal_clkin.hw,
> + [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw,
> + [CLKID_RTC_32K_MUX] = &rtc_32k_mux.hw,
> + [CLKID_RTC_32K] = &rtc_32k.hw,
> + [CLKID_RTC_CLK] = &rtc_clk.hw,
> + [CLKID_SYS_RESET_CTRL] = &sys_reset_ctrl.hw,
> + [CLKID_SYS_PWR_CTRL] = &sys_pwr_ctrl.hw,
> + [CLKID_SYS_PAD_CTRL] = &sys_pad_ctrl.hw,
> + [CLKID_SYS_CTRL] = &sys_ctrl.hw,
> + [CLKID_SYS_TS_PLL] = &sys_ts_pll.hw,
> + [CLKID_SYS_DEV_ARB] = &sys_dev_arb.hw,
> + [CLKID_SYS_MMC_PCLK] = &sys_mmc_pclk.hw,
> + [CLKID_SYS_MAILBOX] = &sys_mailbox.hw,
> + [CLKID_SYS_CPU_CTRL] = &sys_cpu_ctrl.hw,
> + [CLKID_SYS_JTAG_CTRL] = &sys_jtag_ctrl.hw,
> + [CLKID_SYS_IR_CTRL] = &sys_ir_ctrl.hw,
> + [CLKID_SYS_IRQ_CTRL] = &sys_irq_ctrl.hw,
> + [CLKID_SYS_MSR_CLK] = &sys_msr_clk.hw,
> + [CLKID_SYS_ROM] = &sys_rom.hw,
> + [CLKID_SYS_CPU_ARB] = &sys_cpu_apb.hw,
> + [CLKID_SYS_RSA] = &sys_rsa.hw,
> + [CLKID_SYS_SAR_ADC] = &sys_sar_adc.hw,
> + [CLKID_SYS_STARTUP] = &sys_startup.hw,
> + [CLKID_SYS_SECURE] = &sys_secure.hw,
> + [CLKID_SYS_SPIFC] = &sys_spifc.hw,
> + [CLKID_SYS_DSPA] = &sys_dspa.hw,
> + [CLKID_SYS_NNA] = &sys_nna.hw,
> + [CLKID_SYS_ETH_MAC] = &sys_eth_mac.hw,
> + [CLKID_SYS_GIC] = &sys_gic.hw,
> + [CLKID_SYS_RAMA] = &sys_rama.hw,
> + [CLKID_SYS_BIG_NIC] = &sys_big_nic.hw,
> + [CLKID_SYS_RAMB] = &sys_ramb.hw,
> + [CLKID_SYS_AUDIO_TOP] = &sys_audio_top.hw,
> + [CLKID_SYS_AUDIO_VAD] = &sys_audio_vad.hw,
> + [CLKID_SYS_USB] = &sys_usb.hw,
> + [CLKID_SYS_SD_EMMC_A] = &sys_sd_emmc_a.hw,
> + [CLKID_SYS_SD_EMMC_C] = &sys_sd_emmc_c.hw,
> + [CLKID_SYS_PWM_AB] = &sys_pwm_ab.hw,
> + [CLKID_SYS_PWM_CD] = &sys_pwm_cd.hw,
> + [CLKID_SYS_PWM_EF] = &sys_pwm_ef.hw,
> + [CLKID_SYS_PWM_GH] = &sys_pwm_gh.hw,
> + [CLKID_SYS_SPICC_1] = &sys_spicc_1.hw,
> + [CLKID_SYS_SPICC_0] = &sys_spicc_0.hw,
> + [CLKID_SYS_UART_A] = &sys_uart_a.hw,
> + [CLKID_SYS_UART_B] = &sys_uart_b.hw,
> + [CLKID_SYS_UART_C] = &sys_uart_c.hw,
> + [CLKID_SYS_UART_D] = &sys_uart_d.hw,
> + [CLKID_SYS_UART_E] = &sys_uart_e.hw,
> + [CLKID_SYS_I2C_M_A] = &sys_i2c_m_a.hw,
> + [CLKID_SYS_I2C_M_B] = &sys_i2c_m_b.hw,
> + [CLKID_SYS_I2C_M_C] = &sys_i2c_m_c.hw,
> + [CLKID_SYS_I2C_M_D] = &sys_i2c_m_d.hw,
> + [CLKID_SYS_RTC] = &sys_rtc.hw,
> + [CLKID_AXI_AUDIO_VAD] = &axi_audio_vad.hw,
> + [CLKID_AXI_AUDIO_TOP] = &axi_audio_top.hw,
> + [CLKID_AXI_SYS_NIC] = &axi_sys_nic.hw,
> + [CLKID_AXI_RAMB] = &axi_ramb.hw,
> + [CLKID_AXI_RAMA] = &axi_rama.hw,
> + [CLKID_AXI_CPU_DMC] = &axi_cpu_dmc.hw,
> + [CLKID_AXI_NNA] = &axi_nna.hw,
> + [CLKID_AXI_DEV1_DMC] = &axi_dev1_dmc.hw,
> + [CLKID_AXI_DEV0_DMC] = &axi_dev0_dmc.hw,
> + [CLKID_AXI_DSP_DMC] = &axi_dsp_dmc.hw,
> + [CLKID_12_24M_IN] = &clk_12_24m_in.hw,
> + [CLKID_12M_24M] = &clk_12_24m.hw,
> + [CLKID_FCLK_25M_DIV] = &fclk_25m_div.hw,
> + [CLKID_FCLK_25M] = &fclk_25m.hw,
> + [CLKID_GEN_SEL] = &gen_sel.hw,
> + [CLKID_GEN_DIV] = &gen_div.hw,
> + [CLKID_GEN] = &gen.hw,
> + [CLKID_SARADC_SEL] = &saradc_sel.hw,
> + [CLKID_SARADC_DIV] = &saradc_div.hw,
> + [CLKID_SARADC] = &saradc.hw,
> + [CLKID_PWM_A_SEL] = &pwm_a_sel.hw,
> + [CLKID_PWM_A_DIV] = &pwm_a_div.hw,
> + [CLKID_PWM_A] = &pwm_a.hw,
> + [CLKID_PWM_B_SEL] = &pwm_b_sel.hw,
> + [CLKID_PWM_B_DIV] = &pwm_b_div.hw,
> + [CLKID_PWM_B] = &pwm_b.hw,
> + [CLKID_PWM_C_SEL] = &pwm_c_sel.hw,
> + [CLKID_PWM_C_DIV] = &pwm_c_div.hw,
> + [CLKID_PWM_C] = &pwm_c.hw,
> + [CLKID_PWM_D_SEL] = &pwm_d_sel.hw,
> + [CLKID_PWM_D_DIV] = &pwm_d_div.hw,
> + [CLKID_PWM_D] = &pwm_d.hw,
> + [CLKID_PWM_E_SEL] = &pwm_e_sel.hw,
> + [CLKID_PWM_E_DIV] = &pwm_e_div.hw,
> + [CLKID_PWM_E] = &pwm_e.hw,
> + [CLKID_PWM_F_SEL] = &pwm_f_sel.hw,
> + [CLKID_PWM_F_DIV] = &pwm_f_div.hw,
> + [CLKID_PWM_F] = &pwm_f.hw,
> + [CLKID_PWM_G_SEL] = &pwm_g_sel.hw,
> + [CLKID_PWM_G_DIV] = &pwm_g_div.hw,
> + [CLKID_PWM_G] = &pwm_g.hw,
> + [CLKID_PWM_H_SEL] = &pwm_h_sel.hw,
> + [CLKID_PWM_H_DIV] = &pwm_h_div.hw,
> + [CLKID_PWM_H] = &pwm_h.hw,
> + [CLKID_SPICC_0_SEL] = &spicc_0_sel.hw,
> + [CLKID_SPICC_0_DIV] = &spicc_0_div.hw,
> + [CLKID_SPICC_0] = &spicc_0.hw,
> + [CLKID_SPICC_1_SEL] = &spicc_1_sel.hw,
> + [CLKID_SPICC_1_DIV] = &spicc_1_div.hw,
> + [CLKID_SPICC_1] = &spicc_1.hw,
> + [CLKID_SD_EMMC_A_SEL] = &sd_emmc_a_sel.hw,
> + [CLKID_SD_EMMC_A_DIV] = &sd_emmc_a_div.hw,
> + [CLKID_SD_EMMC_A] = &sd_emmc_a.hw,
> + [CLKID_SD_EMMC_C_SEL] = &sd_emmc_c_sel.hw,
> + [CLKID_SD_EMMC_C_DIV] = &sd_emmc_c_div.hw,
> + [CLKID_SD_EMMC_C] = &sd_emmc_c.hw,
> + [CLKID_TS_DIV] = &ts_div.hw,
> + [CLKID_TS] = &ts.hw,
> + [CLKID_ETH_125M_DIV] = ð_125m_div.hw,
> + [CLKID_ETH_125M] = ð_125m.hw,
> + [CLKID_ETH_RMII_DIV] = ð_rmii_div.hw,
> + [CLKID_ETH_RMII] = ð_rmii.hw,
> + [CLKID_DSPA_0_SEL] = &dspa_0_sel.hw,
> + [CLKID_DSPA_0_DIV] = &dspa_0_div.hw,
> + [CLKID_DSPA_0] = &dspa_0.hw,
> + [CLKID_DSPA_1_SEL] = &dspa_1_sel.hw,
> + [CLKID_DSPA_1_DIV] = &dspa_1_div.hw,
> + [CLKID_DSPA_1] = &dspa_1.hw,
> + [CLKID_DSPA] = &dspa.hw,
> + [CLKID_NNA_CORE_SEL] = &nna_core_sel.hw,
> + [CLKID_NNA_CORE_DIV] = &nna_core_div.hw,
> + [CLKID_NNA_CORE] = &nna_core.hw,
> + [CLKID_NNA_AXI_SEL] = &nna_axi_sel.hw,
> + [CLKID_NNA_AXI_DIV] = &nna_axi_div.hw,
> + [CLKID_NNA_AXI] = &nna_axi.hw,
> +};
> +
> +/* Convenience table to populate regmap in .probe */
> +static struct clk_regmap *const a5_periphs_clk_regmaps[] = {
> + &rtc_xtal_clkin,
> + &rtc_32k_div,
> + &rtc_32k_mux,
> + &rtc_32k,
> + &rtc_clk,
> + &sys_reset_ctrl,
> + &sys_pwr_ctrl,
> + &sys_pad_ctrl,
> + &sys_ctrl,
> + &sys_ts_pll,
> + &sys_dev_arb,
> + &sys_mmc_pclk,
> + &sys_mailbox,
> + &sys_cpu_ctrl,
> + &sys_jtag_ctrl,
> + &sys_ir_ctrl,
> + &sys_irq_ctrl,
> + &sys_msr_clk,
> + &sys_rom,
> + &sys_cpu_apb,
> + &sys_rsa,
> + &sys_sar_adc,
> + &sys_startup,
> + &sys_secure,
> + &sys_spifc,
> + &sys_dspa,
> + &sys_nna,
> + &sys_eth_mac,
> + &sys_gic,
> + &sys_rama,
> + &sys_big_nic,
> + &sys_ramb,
> + &sys_audio_top,
> + &sys_audio_vad,
> + &sys_usb,
> + &sys_sd_emmc_a,
> + &sys_sd_emmc_c,
> + &sys_pwm_ab,
> + &sys_pwm_cd,
> + &sys_pwm_ef,
> + &sys_pwm_gh,
> + &sys_spicc_1,
> + &sys_spicc_0,
> + &sys_uart_a,
> + &sys_uart_b,
> + &sys_uart_c,
> + &sys_uart_d,
> + &sys_uart_e,
> + &sys_i2c_m_a,
> + &sys_i2c_m_b,
> + &sys_i2c_m_c,
> + &sys_i2c_m_d,
> + &sys_rtc,
> + &axi_audio_vad,
> + &axi_audio_top,
> + &axi_sys_nic,
> + &axi_ramb,
> + &axi_rama,
> + &axi_cpu_dmc,
> + &axi_nna,
> + &axi_dev1_dmc,
> + &axi_dev0_dmc,
> + &axi_dsp_dmc,
> + &clk_12_24m_in,
> + &clk_12_24m,
> + &fclk_25m_div,
> + &fclk_25m,
> + &gen_sel,
> + &gen_div,
> + &gen,
> + &saradc_sel,
> + &saradc_div,
> + &saradc,
> + &pwm_a_sel,
> + &pwm_a_div,
> + &pwm_a,
> + &pwm_b_sel,
> + &pwm_b_div,
> + &pwm_b,
> + &pwm_c_sel,
> + &pwm_c_div,
> + &pwm_c,
> + &pwm_d_sel,
> + &pwm_d_div,
> + &pwm_d,
> + &pwm_e_sel,
> + &pwm_e_div,
> + &pwm_e,
> + &pwm_f_sel,
> + &pwm_f_div,
> + &pwm_f,
> + &pwm_g_sel,
> + &pwm_g_div,
> + &pwm_g,
> + &pwm_h_sel,
> + &pwm_h_div,
> + &pwm_h,
> + &spicc_0_sel,
> + &spicc_0_div,
> + &spicc_0,
> + &spicc_1_sel,
> + &spicc_1_div,
> + &spicc_1,
> + &sd_emmc_a_sel,
> + &sd_emmc_a_div,
> + &sd_emmc_a,
> + &sd_emmc_c_sel,
> + &sd_emmc_c_div,
> + &sd_emmc_c,
> + &ts_div,
> + &ts,
> + ð_125m,
> + ð_rmii_div,
> + ð_rmii,
> + &dspa_0_sel,
> + &dspa_0_div,
> + &dspa_0,
> + &dspa_1_sel,
> + &dspa_1_div,
> + &dspa_1,
> + &dspa,
> + &nna_core_sel,
> + &nna_core_div,
> + &nna_core,
> + &nna_axi_sel,
> + &nna_axi_div,
> + &nna_axi
> +};
> +
> +static const struct regmap_config clkc_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = CLKCTRL_NNA_CLK_CNTL,
> +};
> +
> +static struct meson_clk_hw_data a5_periphs_clks = {
> + .hws = a5_periphs_hw_clks,
> + .num = ARRAY_SIZE(a5_periphs_hw_clks),
> +};
> +
> +static int aml_a5_peripherals_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct regmap *regmap;
> + void __iomem *base;
> + int clkid, ret, i;
> +
> + base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + /* Populate regmap for the regmap backed clocks */
> + for (i = 0; i < ARRAY_SIZE(a5_periphs_clk_regmaps); i++)
> + a5_periphs_clk_regmaps[i]->map = regmap;
> +
> + for (clkid = 0; clkid < a5_periphs_clks.num; clkid++) {
> + /* array might be sparse */
> + if (!a5_periphs_clks.hws[clkid])
> + continue;
> +
> + ret = devm_clk_hw_register(dev, a5_periphs_clks.hws[clkid]);
> + if (ret) {
> + dev_err(dev, "Clock registration failed\n");
> + return ret;
> + }
> + }
> +
> + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
> + &a5_periphs_clks);
> +}
> +
> +static const struct of_device_id a5_peripherals_clkc_match_table[] = {
> + {
> + .compatible = "amlogic,a5-peripherals-clkc",
> + },
> + { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, a5_peripherals_clkc_match_table);
> +
> +static struct platform_driver a5_peripherals_driver = {
> + .probe = aml_a5_peripherals_probe,
> + .driver = {
> + .name = "a5-peripherals-clkc",
> + .of_match_table = a5_peripherals_clkc_match_table,
> + },
> +};
> +module_platform_driver(a5_peripherals_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A5 Peripherals Clock Controller driver");
> +MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
> +MODULE_LICENSE("GPL");
--
Jerome
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock
2024-09-24 14:45 ` Jerome Brunet
@ 2024-09-29 8:17 ` Xianwei Zhao
2024-09-30 9:41 ` Jerome Brunet
0 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao @ 2024-09-29 8:17 UTC (permalink / raw)
To: Jerome Brunet, Xianwei Zhao via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chuan Liu, Kevin Hilman,
Martin Blumenstingl, linux-amlogic, linux-clk, devicetree,
linux-kernel, linux-arm-kernel
Hi Jerome,
Thanks for your reply.
On 2024/9/24 22:45, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
> On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
>
>> From: Chuan Liu <chuan.liu@amlogic.com>
>>
>> Add the PLL clock controller driver for the Amlogic A5 SoC family.
>>
>> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
>> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
>> ---
>> drivers/clk/meson/Kconfig | 14 ++
>> drivers/clk/meson/Makefile | 1 +
>> drivers/clk/meson/a5-pll.c | 553 +++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 568 insertions(+)
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 78f648c9c97d..2a713276e46c 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -132,6 +132,20 @@ config COMMON_CLK_A1_PERIPHERALS
>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>> controller to work.
>>
>> +config COMMON_CLK_A5_PLL
>> + tristate "Amlogic A5 PLL clock controller"
>> + depends on ARM64
>> + default y
>> + imply ARM_SCMI_PROTOCOL
>
> don't think this is needed, same as c3
>
Will delete it in the next version.
>> + imply COMMON_CLK_SCMI
>> + select COMMON_CLK_MESON_REGMAP
>> + select COMMON_CLK_MESON_PLL
>> + select COMMON_CLK_MESON_CLKC_UTILS
>> + help
>> + Support for the PLL clock controller on Amlogic AV40x device, AKA A5.
>> + Say Y if you want the board to work, because PLLs are the parent
>> + of most peripherals.
>> +
>> config COMMON_CLK_C3_PLL
>> tristate "Amlogic C3 PLL clock controller"
>> depends on ARM64
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index bc56a47931c1..fc4b8a723145 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>> +obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
>> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>> diff --git a/drivers/clk/meson/a5-pll.c b/drivers/clk/meson/a5-pll.c
>> new file mode 100644
>> index 000000000000..d96ed72ef8d4
>> --- /dev/null
>> +++ b/drivers/clk/meson/a5-pll.c
>> @@ -0,0 +1,553 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Amlogic A5 PLL Controller Driver
>> + *
>> + * Copyright (c) 2024 Amlogic, inc.
>> + * Author: Chuan Liu <chuan.liu@amlogic.com>
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/platform_device.h>
>> +#include "clk-regmap.h"
>> +#include "clk-pll.h"
>> +#include "clk-mpll.h"
>
> Kconfig does not select support for this, so something is odd.
Will add select COMMON_CLK_MESON_MPLL in Kconfig file
>
>> +#include "meson-clkc-utils.h"
>> +#include <dt-bindings/clock/amlogic,a5-pll-clkc.h>
>> +
>> +#define ANACTRL_FIXPLL_CTRL1 0x44
>> +#define ANACTRL_GP0PLL_CTRL0 0x80
>> +#define ANACTRL_GP0PLL_CTRL1 0x84
>> +#define ANACTRL_GP0PLL_CTRL2 0x88
>> +#define ANACTRL_GP0PLL_CTRL3 0x8c
>> +#define ANACTRL_GP0PLL_CTRL4 0x90
>> +#define ANACTRL_GP0PLL_CTRL5 0x94
>> +#define ANACTRL_GP0PLL_CTRL6 0x98
>> +#define ANACTRL_HIFIPLL_CTRL0 0x100
>> +#define ANACTRL_HIFIPLL_CTRL1 0x104
>> +#define ANACTRL_HIFIPLL_CTRL2 0x108
>> +#define ANACTRL_HIFIPLL_CTRL3 0x10c
>> +#define ANACTRL_HIFIPLL_CTRL4 0x110
>> +#define ANACTRL_HIFIPLL_CTRL5 0x114
>> +#define ANACTRL_HIFIPLL_CTRL6 0x118
>> +#define ANACTRL_MPLL_CTRL0 0x180
>> +#define ANACTRL_MPLL_CTRL1 0x184
>> +#define ANACTRL_MPLL_CTRL2 0x188
>> +#define ANACTRL_MPLL_CTRL3 0x18c
>> +#define ANACTRL_MPLL_CTRL4 0x190
>> +#define ANACTRL_MPLL_CTRL5 0x194
>> +#define ANACTRL_MPLL_CTRL6 0x198
>> +#define ANACTRL_MPLL_CTRL7 0x19c
>> +#define ANACTRL_MPLL_CTRL8 0x1a0
>> +
>> +static DEFINE_SPINLOCK(aml_clk_lock);
>
> Re-submit you lock patch first and adjust please.
>
Will do.
>> +
>> +static struct clk_fixed_factor mpll_prediv = {
>> + .mult = 1,
>> + .div = 2,
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll_prediv",
>> + .ops = &clk_fixed_factor_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "fix_dco"
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static const struct reg_sequence mpll0_init_regs[] = {
>> + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 },
>> +};
>> +
>> +static struct clk_regmap mpll0_div = {
>> + .data = &(struct meson_clk_mpll_data){
>> + .sdm = {
>> + .reg_off = ANACTRL_MPLL_CTRL1,
>> + .shift = 0,
>> + .width = 14,
>> + },
>> + .sdm_en = {
>> + .reg_off = ANACTRL_MPLL_CTRL1,
>> + .shift = 30,
>> + .width = 1,
>> + },
>> + .n2 = {
>> + .reg_off = ANACTRL_MPLL_CTRL1,
>> + .shift = 20,
>> + .width = 9,
>> + },
>> + .ssen = {
>> + .reg_off = ANACTRL_MPLL_CTRL1,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .lock = &aml_clk_lock,
>> + .init_regs = mpll0_init_regs,
>> + .init_count = ARRAY_SIZE(mpll0_init_regs),
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll0_div",
>> + .ops = &meson_clk_mpll_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &mpll_prediv.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap mpll0 = {
>> + .data = &(struct clk_regmap_gate_data){
>> + .offset = ANACTRL_MPLL_CTRL1,
>> + .bit_idx = 31,
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll0",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) { &mpll0_div.hw },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct reg_sequence mpll1_init_regs[] = {
>> + { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 },
>> +};
>> +
>> +static struct clk_regmap mpll1_div = {
>> + .data = &(struct meson_clk_mpll_data){
>> + .sdm = {
>> + .reg_off = ANACTRL_MPLL_CTRL3,
>> + .shift = 0,
>> + .width = 14,
>> + },
>> + .sdm_en = {
>> + .reg_off = ANACTRL_MPLL_CTRL3,
>> + .shift = 30,
>> + .width = 1,
>> + },
>> + .n2 = {
>> + .reg_off = ANACTRL_MPLL_CTRL3,
>> + .shift = 20,
>> + .width = 9,
>> + },
>> + .ssen = {
>> + .reg_off = ANACTRL_MPLL_CTRL3,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .lock = &aml_clk_lock,
>> + .init_regs = mpll1_init_regs,
>> + .init_count = ARRAY_SIZE(mpll1_init_regs),
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll1_div",
>> + .ops = &meson_clk_mpll_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &mpll_prediv.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap mpll1 = {
>> + .data = &(struct clk_regmap_gate_data){
>> + .offset = ANACTRL_MPLL_CTRL3,
>> + .bit_idx = 31,
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll1",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) { &mpll1_div.hw },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct reg_sequence mpll2_init_regs[] = {
>> + { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 },
>> +};
>> +
>> +static struct clk_regmap mpll2_div = {
>> + .data = &(struct meson_clk_mpll_data){
>> + .sdm = {
>> + .reg_off = ANACTRL_MPLL_CTRL5,
>> + .shift = 0,
>> + .width = 14,
>> + },
>> + .sdm_en = {
>> + .reg_off = ANACTRL_MPLL_CTRL5,
>> + .shift = 30,
>> + .width = 1,
>> + },
>> + .n2 = {
>> + .reg_off = ANACTRL_MPLL_CTRL5,
>> + .shift = 20,
>> + .width = 9,
>> + },
>> + .ssen = {
>> + .reg_off = ANACTRL_MPLL_CTRL5,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .lock = &aml_clk_lock,
>> + .init_regs = mpll2_init_regs,
>> + .init_count = ARRAY_SIZE(mpll2_init_regs),
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll2_div",
>> + .ops = &meson_clk_mpll_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &mpll_prediv.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap mpll2 = {
>> + .data = &(struct clk_regmap_gate_data){
>> + .offset = ANACTRL_MPLL_CTRL5,
>> + .bit_idx = 31,
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll2",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) { &mpll2_div.hw },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct reg_sequence mpll3_init_regs[] = {
>> + { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 },
>> +};
>> +
>> +static struct clk_regmap mpll3_div = {
>> + .data = &(struct meson_clk_mpll_data){
>> + .sdm = {
>> + .reg_off = ANACTRL_MPLL_CTRL7,
>> + .shift = 0,
>> + .width = 14,
>> + },
>> + .sdm_en = {
>> + .reg_off = ANACTRL_MPLL_CTRL7,
>> + .shift = 30,
>> + .width = 1,
>> + },
>> + .n2 = {
>> + .reg_off = ANACTRL_MPLL_CTRL7,
>> + .shift = 20,
>> + .width = 9,
>> + },
>> + .ssen = {
>> + .reg_off = ANACTRL_MPLL_CTRL7,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .lock = &aml_clk_lock,
>> + .init_regs = mpll3_init_regs,
>> + .init_count = ARRAY_SIZE(mpll3_init_regs),
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll3_div",
>> + .ops = &meson_clk_mpll_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &mpll_prediv.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap mpll3 = {
>> + .data = &(struct clk_regmap_gate_data){
>> + .offset = ANACTRL_MPLL_CTRL7,
>> + .bit_idx = 31,
>> + },
>> + .hw.init = &(struct clk_init_data){
>> + .name = "mpll3",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) { &mpll3_div.hw },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct reg_sequence gp0_init_regs[] = {
>> + { .reg = ANACTRL_GP0PLL_CTRL0, .def = 0X08000000 },
>> + { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 },
>> + { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 },
>> + { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x6a295c00 },
>> + { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x65771290 },
>> + { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a },
>> + { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x54540000 }
>> +};
>> +
>> +static const struct pll_mult_range gp0_pll_mult_range = {
>> + .min = 125,
>> + .max = 250,
>> +};
>> +
>> +static struct clk_regmap gp0_pll_dco = {
>> + .data = &(struct meson_clk_pll_data) {
>> + .en = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 28,
>> + .width = 1,
>> + },
>> + .m = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 0,
>> + .width = 8,
>> + },
>> + .frac = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL1,
>> + .shift = 0,
>> + .width = 17,
>> + },
>> + .n = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 10,
>> + .width = 5,
>> + },
>> + .l = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 31,
>> + .width = 1,
>> + },
>> + .rst = {
>> + .reg_off = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .range = &gp0_pll_mult_range,
>> + .init_regs = gp0_init_regs,
>> + .init_count = ARRAY_SIZE(gp0_init_regs),
>> + .frac_max = 100000,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "gp0_pll_dco",
>> + .ops = &meson_clk_pll_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "xtal_24m",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +/* The maximum frequency divider supports is 16, not 128(2^7) */
>> +static const struct clk_div_table gp0_pll_od_table[] = {
>> + { 0, 1 },
>> + { 1, 2 },
>> + { 2, 4 },
>> + { 3, 8 },
>> + { 4, 16 },
>> + { 5, 32 },
>> + { /* sentinel */ }
>> +};
>> +
>> +static struct clk_regmap gp0_pll = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = ANACTRL_GP0PLL_CTRL0,
>> + .shift = 16,
>> + .width = 3,
>> + .table = gp0_pll_od_table,
>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "gp0_pll",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &gp0_pll_dco.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct reg_sequence hifi_init_regs[] = {
>> + { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0X08000000 },
>
> What is bit you are flipping in CTRL0 ? it is suspicious
>
Yes, CTRL0 and CTRL1 are not necessary here and will be removed in the
next version.
>> + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00000000 },
>> + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
>> + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a295c00 },
>> + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
>> + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
>> + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x54540000 }
>> +};
>> +
>> +static const struct pll_mult_range hifi_pll_mult_range = {
>> + .min = 125,
>> + .max = 250,
>> +};
>> +
>> +static struct clk_regmap hifi_pll_dco = {
>> + .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,
>> + },
>> + .frac = {
>> + .reg_off = ANACTRL_HIFIPLL_CTRL1,
>> + .shift = 0,
>> + .width = 17,
>> + },
>> + .n = {
>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>> + .shift = 10,
>> + .width = 5,
>> + },
>> + .l = {
>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>> + .shift = 31,
>> + .width = 1,
>> + },
>> + .rst = {
>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>> + .shift = 29,
>> + .width = 1,
>> + },
>> + .range = &hifi_pll_mult_range,
>> + .init_regs = hifi_init_regs,
>> + .init_count = ARRAY_SIZE(hifi_init_regs),
>> + .frac_max = 100000,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "hifi_pll_dco",
>> + .ops = &meson_clk_pll_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "xtal_24m",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +/* The maximum frequency divider supports is 16, not 128(2^7) */
>> +static const struct clk_div_table hifi_pll_od_table[] = {
>> + { 0, 1 },
>> + { 1, 2 },
>> + { 2, 4 },
>> + { 3, 8 },
>
> Why don't you ajust the mask then ? Looks like a POW_OF_2 basic
> dividider to me.
>
The maximum frequency division value above the design document is 8,
such as the configuration 4/5/6... The actual frequency division value
is still 8, so this table is defined, why there is this restriction in
detail I am not clear about.
Will add these comment ot describe it.
>> + { /* sentinel */ }
>> +};
>> +
>> +static struct clk_regmap hifi_pll = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = ANACTRL_HIFIPLL_CTRL0,
>> + .shift = 16,
>> + .width = 3,
>> + .table = hifi_pll_od_table,
>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "hifi_pll",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &hifi_pll_dco.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_hw *a5_pll_hw_clks[] = {
>> + [CLKID_MPLL_PREDIV] = &mpll_prediv.hw,
>> + [CLKID_MPLL0_DIV] = &mpll0_div.hw,
>> + [CLKID_MPLL0] = &mpll0.hw,
>> + [CLKID_MPLL1_DIV] = &mpll1_div.hw,
>> + [CLKID_MPLL1] = &mpll1.hw,
>> + [CLKID_MPLL2_DIV] = &mpll2_div.hw,
>> + [CLKID_MPLL2] = &mpll2.hw,
>> + [CLKID_MPLL3_DIV] = &mpll3_div.hw,
>> + [CLKID_MPLL3] = &mpll3.hw,
>> + [CLKID_GP0_PLL_DCO] = &gp0_pll_dco.hw,
>> + [CLKID_GP0_PLL] = &gp0_pll.hw,
>> + [CLKID_HIFI_PLL_DCO] = &hifi_pll_dco.hw,
>> + [CLKID_HIFI_PLL] = &hifi_pll.hw
>> +};
>> +
>> +/* Convenience table to populate regmap in .probe */
>> +static struct clk_regmap *const a5_pll_clk_regmaps[] = {
>> + &mpll0_div,
>> + &mpll0,
>> + &mpll1_div,
>> + &mpll1,
>> + &mpll2_div,
>> + &mpll2,
>> + &mpll3_div,
>> + &mpll3,
>> + &gp0_pll_dco,
>> + &gp0_pll,
>> + &hifi_pll_dco,
>> + &hifi_pll
>> +};
>> +
>> +static const struct regmap_config clkc_regmap_config = {
>> + .reg_bits = 32,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> + .max_register = ANACTRL_MPLL_CTRL8,
>> +};
>> +
>> +static struct meson_clk_hw_data a5_pll_clks = {
>> + .hws = a5_pll_hw_clks,
>> + .num = ARRAY_SIZE(a5_pll_hw_clks),
>> +};
>> +
>> +static int aml_a5_pll_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct regmap *regmap;
>> + void __iomem *base;
>> + int clkid, ret, i;
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
>> + if (IS_ERR(regmap))
>> + return PTR_ERR(regmap);
>> +
>> + /* Populate regmap for the regmap backed clocks */
>> + for (i = 0; i < ARRAY_SIZE(a5_pll_clk_regmaps); i++)
>> + a5_pll_clk_regmaps[i]->map = regmap;
>> +
>> + for (clkid = 0; clkid < a5_pll_clks.num; clkid++) {
>> + /* array might be sparse */
>> + if (!a5_pll_clks.hws[clkid])
>> + continue;
>> +
>> + ret = devm_clk_hw_register(dev, a5_pll_clks.hws[clkid]);
>> + if (ret) {
>> + dev_err(dev, "Clock registration failed\n");
>> + return ret;
>> + }
>> + }
>> +
>> + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
>> + &a5_pll_clks);
>> +}
>> +
>> +static const struct of_device_id a5_pll_clkc_match_table[] = {
>> + {
>> + .compatible = "amlogic,a5-pll-clkc",
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, a5_pll_clkc_match_table);
>> +
>> +static struct platform_driver a5_pll_driver = {
>> + .probe = aml_a5_pll_probe,
>> + .driver = {
>> + .name = "a5-pll-clkc",
>> + .of_match_table = a5_pll_clkc_match_table,
>> + },
>> +};
>> +module_platform_driver(a5_pll_driver);
>> +
>> +MODULE_DESCRIPTION("Amlogic A5 PLL Clock Controller driver");
>> +MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
>> +MODULE_LICENSE("GPL");
>
> --
> Jerome
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver
2024-09-24 15:09 ` Jerome Brunet
@ 2024-09-29 8:44 ` Xianwei Zhao
2024-09-30 10:16 ` Jerome Brunet
0 siblings, 1 reply; 17+ messages in thread
From: Xianwei Zhao @ 2024-09-29 8:44 UTC (permalink / raw)
To: Jerome Brunet, Xianwei Zhao via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chuan Liu, Kevin Hilman,
Martin Blumenstingl, linux-amlogic, linux-clk, devicetree,
linux-kernel, linux-arm-kernel
Hi Jerome,
Thanks for your reply.
On 2024/9/24 23:09, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
> On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
>
>> From: Chuan Liu <chuan.liu@amlogic.com>
>>
>> Add the peripherals clock controller driver in the A5 SoC family.
>>
>> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
>> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
>> ---
>> drivers/clk/meson/Kconfig | 14 +
>> drivers/clk/meson/Makefile | 1 +
>> drivers/clk/meson/a5-peripherals.c | 1471 ++++++++++++++++++++++++++++++++++++
>> 3 files changed, 1486 insertions(+)
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index 2a713276e46c..21845edcd8ef 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -146,6 +146,20 @@ config COMMON_CLK_A5_PLL
>> Say Y if you want the board to work, because PLLs are the parent
>> of most peripherals.
>>
>> +config COMMON_CLK_A5_PERIPHERALS
>> + tristate "Amlogic A5 peripherals clock controller"
>> + depends on ARM64
>> + default y
>> + imply ARM_SCMI_PROTOCOL
>
> same
>
Will do.
>> + imply COMMON_CLK_SCMI
>> + imply COMMON_CLK_A5_PLL
>> + select COMMON_CLK_MESON_REGMAP
>> + select COMMON_CLK_MESON_DUALDIV
>> + select COMMON_CLK_MESON_CLKC_UTILS
>> + help
>> + Support for the Peripherals clock controller on Amlogic AV40x device,
>> + AKA A5. Say Y if you want the peripherals clock to work.
>> +
>> config COMMON_CLK_C3_PLL
>> tristate "Amlogic C3 PLL clock controller"
>> depends on ARM64
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index fc4b8a723145..58236c6e8377 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -21,6 +21,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>> obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
>> +obj-$(CONFIG_COMMON_CLK_A5_PERIPHERALS) += a5-peripherals.o
>> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>> diff --git a/drivers/clk/meson/a5-peripherals.c b/drivers/clk/meson/a5-peripherals.c
>> new file mode 100644
>> index 000000000000..c28da340a5af
>> --- /dev/null
>> +++ b/drivers/clk/meson/a5-peripherals.c
>> @@ -0,0 +1,1471 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Amlogic A5 Peripherals Clock Controller Driver
>> + *
>> + * Copyright (c) 2024 Amlogic, inc.
>> + * Author: Chuan Liu <chuan.liu@amlogic.com>
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/platform_device.h>
>> +#include "clk-regmap.h"
>> +#include "clk-dualdiv.h"
>> +#include "meson-clkc-utils.h"
>> +#include <dt-bindings/clock/amlogic,a5-peripherals-clkc.h>
>> +
>> +#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x8
>> +#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0xc
>> +#define CLKCTRL_RTC_CTRL 0x10
>> +#define CLKCTRL_SYS_CLK_EN0_REG0 0x44
>> +#define CLKCTRL_SYS_CLK_EN0_REG1 0x48
>> +#define CLKCTRL_DSPA_CLK_CTRL0 0x9c
>> +#define CLKCTRL_CLK12_24_CTRL 0xa8
>> +#define CLKCTRL_AXI_CLK_EN0 0xac
>> +#define CLKCTRL_TS_CLK_CTRL 0x158
>> +#define CLKCTRL_ETH_CLK_CTRL 0x164
>> +#define CLKCTRL_NAND_CLK_CTRL 0x168
>> +#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c
>> +#define CLKCTRL_SPICC_CLK_CTRL 0x174
>> +#define CLKCTRL_GEN_CLK_CTRL 0x178
>> +#define CLKCTRL_SAR_CLK_CTRL0 0x17c
>> +#define CLKCTRL_PWM_CLK_AB_CTRL 0x180
>> +#define CLKCTRL_PWM_CLK_CD_CTRL 0x184
>> +#define CLKCTRL_PWM_CLK_EF_CTRL 0x188
>> +#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c
>> +#define CLKCTRL_NNA_CLK_CNTL 0x220
>
> Again I see a lot of holes in there. Please make sure there is only
> clocks in the whole region you are claiming for the device.
>
> Otherwise it is fine to register as many controller as necessary
>
This has been verified to not overlap the register fields of other
controllers.
>> +
>> +static struct clk_regmap rtc_xtal_clkin = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
>> + .bit_idx = 31,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "rtc_xtal_clkin",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "oscin",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static const struct meson_clk_dualdiv_param rtc_32k_div_table[] = {
>> + { 733, 732, 8, 11, 1 },
>> + { /* sentinel */ }
>> +};
>> +
>> +static struct clk_regmap rtc_32k_div = {
>> + .data = &(struct meson_clk_dualdiv_data) {
>> + .n1 = {
>> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
>> + .shift = 0,
>> + .width = 12,
>> + },
>> + .n2 = {
>> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
>> + .shift = 12,
>> + .width = 12,
>> + },
>> + .m1 = {
>> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
>> + .shift = 0,
>> + .width = 12,
>> + },
>> + .m2 = {
>> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1,
>> + .shift = 12,
>> + .width = 12,
>> + },
>> + .dual = {
>> + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0,
>> + .shift = 28,
>> + .width = 1,
>> + },
>> + .table = rtc_32k_div_table,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "rtc_32k_div",
>> + .ops = &meson_clk_dualdiv_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &rtc_xtal_clkin.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static const struct clk_parent_data rtc_32k_mux_parent_data[] = {
>> + { .hw = &rtc_32k_div.hw },
>> + { .hw = &rtc_xtal_clkin.hw }
>> +};
>> +
>> +static struct clk_regmap rtc_32k_mux = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL1,
>> + .mask = 0x1,
>> + .shift = 24,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "rtc_32k_mux",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = rtc_32k_mux_parent_data,
>> + .num_parents = ARRAY_SIZE(rtc_32k_mux_parent_data),
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap rtc_32k = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0,
>> + .bit_idx = 30,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "rtc_32k",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &rtc_32k_mux.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct clk_parent_data rtc_clk_mux_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .hw = &rtc_32k.hw },
>> + { .fw_name = "pad_osc" }
>> +};
>> +
>> +static struct clk_regmap rtc_clk = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_RTC_CTRL,
>> + .mask = 0x3,
>> + .shift = 0,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "rtc_clk",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = rtc_clk_mux_parent_data,
>> + .num_parents = ARRAY_SIZE(rtc_clk_mux_parent_data),
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +#define A4_CLK_GATE(_name, _reg, _bit, _fw_name, _ops, _flags)
>> \
>
> A4 ??? everything else is A5 ? Please explain
>
This is a mistake. Will define macro in common head file.
>> +struct clk_regmap _name = { \
>> + .data = &(struct clk_regmap_gate_data){ \
>> + .offset = (_reg), \
>> + .bit_idx = (_bit), \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = #_name, \
>> + .ops = _ops, \
>> + .parent_data = &(const struct clk_parent_data) { \
>> + .fw_name = #_fw_name, \
>> + }, \
>> + .num_parents = 1, \
>> + .flags = (_flags), \
>> + }, \
>> +}
>> +
>> +#define A4_SYS_GATE(_name, _reg, _bit, _flags) \
>> + A4_CLK_GATE(_name, _reg, _bit, sysclk, \
>> + &clk_regmap_gate_ops, _flags)
>> +
>> +#define A4_SYS_GATE_RO(_name, _reg, _bit) \
>> + A4_CLK_GATE(_name, _reg, _bit, sysclk, \
>> + &clk_regmap_gate_ro_ops, 0)
>
> Looks like a copy/paste of the C3. If this pattern keeps on repeating,
> it would be nice to make a common definition
>
Will do.
>> +
>> +static A4_SYS_GATE(sys_reset_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 1, 0);
>> +static A4_SYS_GATE(sys_pwr_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 3, 0);
>> +static A4_SYS_GATE(sys_pad_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 4, 0);
>> +static A4_SYS_GATE(sys_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 5, 0);
>> +static A4_SYS_GATE(sys_ts_pll, CLKCTRL_SYS_CLK_EN0_REG0, 6, 0);
>> +
>> +/*
>> + * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that
>> + * access the AXI bus.
>> + */
>> +static A4_SYS_GATE(sys_dev_arb, CLKCTRL_SYS_CLK_EN0_REG0, 7, 0);
>> +
>> +/*
>> + * FIXME: sys_mmc_pclk provides the clock for the DDR PHY, DDR will only be
>> + * initialized in bl2, and this clock should not be touched in linux.
>> + */
>> +static A4_SYS_GATE_RO(sys_mmc_pclk, CLKCTRL_SYS_CLK_EN0_REG0, 8);
>> +static A4_SYS_GATE(sys_mailbox, CLKCTRL_SYS_CLK_EN0_REG0, 10, 0);
>> +
>> +/*
>> + * NOTE: sys_cpu_ctrl provides the clock for CPU controller. After clock is
>> + * disabled, cpu_clk and other key CPU-related configurations cannot take effect.
>> + */
>> +static A4_SYS_GATE(sys_cpu_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL);
>> +static A4_SYS_GATE(sys_jtag_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 12, 0);
>> +static A4_SYS_GATE(sys_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 13, 0);
>> +
>> +/*
>> + * NOTE: sys_irq_ctrl provides the clock for IRQ controller. The IRQ controller
>> + * collects and distributes the interrupt signal to the GIC, PWR_CTRL, and
>> + * AOCPU. If the clock is disabled, interrupt-related functions will occurs an
>> + * exception.
>> + */
>> +static A4_SYS_GATE(sys_irq_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL);
>> +static A4_SYS_GATE(sys_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 15, 0);
>> +static A4_SYS_GATE(sys_rom, CLKCTRL_SYS_CLK_EN0_REG0, 16, 0);
>> +static A4_SYS_GATE(sys_cpu_apb, CLKCTRL_SYS_CLK_EN0_REG0, 18, 0);
>> +static A4_SYS_GATE(sys_rsa, CLKCTRL_SYS_CLK_EN0_REG0, 19, 0);
>> +static A4_SYS_GATE(sys_sar_adc, CLKCTRL_SYS_CLK_EN0_REG0, 20, 0);
>> +static A4_SYS_GATE(sys_startup, CLKCTRL_SYS_CLK_EN0_REG0, 21, 0);
>> +static A4_SYS_GATE(sys_secure, CLKCTRL_SYS_CLK_EN0_REG0, 22, 0);
>> +static A4_SYS_GATE(sys_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 23, 0);
>> +static A4_SYS_GATE(sys_dspa, CLKCTRL_SYS_CLK_EN0_REG0, 24, 0);
>> +static A4_SYS_GATE(sys_nna, CLKCTRL_SYS_CLK_EN0_REG0, 25, 0);
>> +static A4_SYS_GATE(sys_eth_mac, CLKCTRL_SYS_CLK_EN0_REG0, 26, 0);
>> +
>> +/*
>> + * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller).
>> + * After clock is disabled, The GIC cannot work properly. At present, the driver
>> + * used by our GIC is the public driver in kernel, and there is no management
>> + * clock in the driver.
>> + */
>> +static A4_SYS_GATE(sys_gic, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL);
>
> The GIC has a driver. If it needs clock, maybe it should request it and
> enable it, maybe as optional.
>
This has been explained in C3. GIC is a public driver that does not
reference clock, so you suggest setting it as CRITICAL and adding the
"FIXME" annotation.
>> +static A4_SYS_GATE(sys_rama, CLKCTRL_SYS_CLK_EN0_REG0, 28, 0);
>> +
>> +/*
>> + * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network
>> + * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC,
>> + * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the
>> + * system. After clock is disabled, The NIC cannot work.
>> + */
>
> This comment looks like a clock that should be passed as ressource to a
> bus or power-domain to be properly manage. This is a pattern that keeps
> on repeating. I will not block you on it this time around but I strong
> suggest you fix up the situation on the related platform. Next time
> around, the reason won't be a valid one.
>
There are too many modules associated with this clock... The most
important is the inclusion of some system-level modules that are not
managed by the driver in the kernel and cannot close their clocks,
perhaps it is not appropriate to describe it here.
In the next version I moved it to scmi-clk for management?
>> +static A4_SYS_GATE(sys_big_nic, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL);
>> +static A4_SYS_GATE(sys_ramb, CLKCTRL_SYS_CLK_EN0_REG0, 30, 0);
>> +static A4_SYS_GATE(sys_audio_top, CLKCTRL_SYS_CLK_EN0_REG1, 0, 0);
>> +static A4_SYS_GATE(sys_audio_vad, CLKCTRL_SYS_CLK_EN0_REG1, 1, 0);
>> +static A4_SYS_GATE(sys_usb, CLKCTRL_SYS_CLK_EN0_REG1, 2, 0);
>> +static A4_SYS_GATE(sys_sd_emmc_a, CLKCTRL_SYS_CLK_EN0_REG1, 3, 0);
>> +static A4_SYS_GATE(sys_sd_emmc_c, CLKCTRL_SYS_CLK_EN0_REG1, 4, 0);
>> +static A4_SYS_GATE(sys_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG1, 5, 0);
>> +static A4_SYS_GATE(sys_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG1, 6, 0);
>> +static A4_SYS_GATE(sys_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG1, 7, 0);
>> +static A4_SYS_GATE(sys_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG1, 8, 0);
>> +static A4_SYS_GATE(sys_spicc_1, CLKCTRL_SYS_CLK_EN0_REG1, 9, 0);
>> +static A4_SYS_GATE(sys_spicc_0, CLKCTRL_SYS_CLK_EN0_REG1, 10, 0);
>> +static A4_SYS_GATE(sys_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 11, 0);
>> +static A4_SYS_GATE(sys_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 12, 0);
>> +static A4_SYS_GATE(sys_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 13, 0);
>> +static A4_SYS_GATE(sys_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 14, 0);
>> +static A4_SYS_GATE(sys_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 15, 0);
>> +static A4_SYS_GATE(sys_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 16, 0);
>> +static A4_SYS_GATE(sys_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 17, 0);
>> +static A4_SYS_GATE(sys_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG1, 18, 0);
>> +static A4_SYS_GATE(sys_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG1, 19, 0);
>> +static A4_SYS_GATE(sys_rtc, CLKCTRL_SYS_CLK_EN0_REG1, 21, 0);
>> +
>> +#define A4_AXI_GATE(_name, _reg, _bit, _flags) \
>> + A4_CLK_GATE(_name, _reg, _bit, axiclk, \
>> + &clk_regmap_gate_ops, _flags)
>> +
>> +static A4_AXI_GATE(axi_audio_vad, CLKCTRL_AXI_CLK_EN0, 0, 0);
>> +static A4_AXI_GATE(axi_audio_top, CLKCTRL_AXI_CLK_EN0, 1, 0);
>> +
>> +/*
>> + * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After
>> + * clock is disabled, The NIC cannot work.
>> + */
>> +static A4_AXI_GATE(axi_sys_nic, CLKCTRL_AXI_CLK_EN0, 2, CLK_IS_CRITICAL);
>> +static A4_AXI_GATE(axi_ramb, CLKCTRL_AXI_CLK_EN0, 5, 0);
>> +static A4_AXI_GATE(axi_rama, CLKCTRL_AXI_CLK_EN0, 6, 0);
>> +
>> +/*
>> + * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses
>> + * the DDR. After clock is disabled, The CPU will not have access to the DDR.
>> + */
>> +static A4_AXI_GATE(axi_cpu_dmc, CLKCTRL_AXI_CLK_EN0, 7, CLK_IS_CRITICAL);
>> +static A4_AXI_GATE(axi_nna, CLKCTRL_AXI_CLK_EN0, 12, 0);
>> +
>> +/*
>> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
>> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
>> + */
>
> Same.
>
These normal peripheral drivers manage the clock without a problem.
>> +static A4_AXI_GATE(axi_dev1_dmc, CLKCTRL_AXI_CLK_EN0, 13, 0);
>> +
>> +/*
>> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
>> + * to access the AXI bus of the DDR.
>> + */
>> +static A4_AXI_GATE(axi_dev0_dmc, CLKCTRL_AXI_CLK_EN0, 14, 0);
>> +static A4_AXI_GATE(axi_dsp_dmc, CLKCTRL_AXI_CLK_EN0, 15, 0);
>> +
>> +static struct clk_regmap clk_12_24m_in = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_CLK12_24_CTRL,
>> + .bit_idx = 11,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "clk_12_24m_in",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "xtal_24m",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap clk_12_24m = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_CLK12_24_CTRL,
>> + .shift = 10,
>> + .width = 1,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "clk_12_24m",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &clk_12_24m_in.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +/* FIXME: set value 0 will div by 2 like value 1 */
>
> Again, it is fine when it happens once, like the c3.
> When the pattern starts repeating, it is time to do something about it.
>
The corresponding suggestions have been made to the hardware designer,
but now the designed chip cannot be repaired.
>> +static struct clk_regmap fclk_25m_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_CLK12_24_CTRL,
>> + .shift = 0,
>> + .width = 8,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "fclk_25m_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "fix",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap fclk_25m = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_CLK12_24_CTRL,
>> + .bit_idx = 12,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "fclk_25m",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &fclk_25m_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +/*
>> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk)
>> + * is manged by clock measures module. Their hardware are out of clock tree.
>
> Yet, they exist and should be part of the bindings since they are
> obviously input to this clock.
>
Will add it to bindings, as optional input clock source.
>> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
>> + *
>> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
>> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug purposes.
>> + */
>> +static u32 gen_parent_table[] = { 0, 1, 2, 6, 7, 17, 19, 20, 21, 22, 23, 24, 25,
>> + 26, 27, 28};
>> +
>> +static const struct clk_parent_data gen_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .hw = &rtc_clk.hw },
>> + { .fw_name = "sysplldiv16" },
>> + { .fw_name = "gp1" },
>> + { .fw_name = "hifi" },
>> + { .fw_name = "cpudiv16" },
>> + { .fw_name = "fdiv2" },
>> + { .fw_name = "fdiv2p5" },
>> + { .fw_name = "fdiv3" },
>> + { .fw_name = "fdiv4" },
>> + { .fw_name = "fdiv5" },
>> + { .fw_name = "fdiv7" },
>> + { .fw_name = "mpll0" },
>> + { .fw_name = "mpll1" },
>> + { .fw_name = "mpll2" },
>> + { .fw_name = "mpll3" }
>> +};
>> +
>> +static struct clk_regmap gen_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_GEN_CLK_CTRL,
>> + .mask = 0x1f,
>> + .shift = 12,
>> + .table = gen_parent_table,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "gen_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = gen_parent_data,
>> + .num_parents = ARRAY_SIZE(gen_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap gen_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_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 *[]) {
>> + &gen_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap gen = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_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 *[]) {
>> + &gen_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct clk_parent_data saradc_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .fw_name = "sysclk" }
>> +};
>> +
>> +static struct clk_regmap saradc_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_SAR_CLK_CTRL0,
>> + .mask = 0x1,
>> + .shift = 9,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "saradc_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = saradc_parent_data,
>> + .num_parents = ARRAY_SIZE(saradc_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap saradc_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_SAR_CLK_CTRL0,
>> + .shift = 0,
>> + .width = 8,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "saradc_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &saradc_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap saradc = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_SAR_CLK_CTRL0,
>> + .bit_idx = 8,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "saradc",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &saradc_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct clk_parent_data pwm_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .hw = &rtc_clk.hw },
>> + { .fw_name = "fdiv4" },
>> + { .fw_name = "fdiv3" }
>> +};
>> +
>> +#define AML_PWM_CLK_MUX(_name, _reg, _shift) { \
>> + .data = &(struct clk_regmap_mux_data) { \
>> + .offset = _reg, \
>> + .mask = 0x3, \
>> + .shift = _shift, \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = #_name "_sel", \
>> + .ops = &clk_regmap_mux_ops, \
>> + .parent_data = pwm_parent_data, \
>> + .num_parents = ARRAY_SIZE(pwm_parent_data), \
>> + }, \
>> +}
>> +
>> +#define AML_PWM_CLK_DIV(_name, _reg, _shift) { \
>> + .data = &(struct clk_regmap_div_data) { \
>> + .offset = _reg, \
>> + .shift = _shift, \
>> + .width = 8, \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = #_name "_div", \
>> + .ops = &clk_regmap_divider_ops, \
>> + .parent_names = (const char *[]) { #_name "_sel" },\
>> + .num_parents = 1, \
>> + .flags = CLK_SET_RATE_PARENT, \
>> + }, \
>> +}
>> +
>> +#define AML_PWM_CLK_GATE(_name, _reg, _bit) { \
>> + .data = &(struct clk_regmap_gate_data) { \
>> + .offset = _reg, \
>> + .bit_idx = _bit, \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = #_name, \
>> + .ops = &clk_regmap_gate_ops, \
>> + .parent_names = (const char *[]) { #_name "_div" },\
>> + .num_parents = 1, \
>> + .flags = CLK_SET_RATE_PARENT, \
>> + }, \
>> +}
>
> Now the prefix is just AML ? please be consistent
> And again, looks like a repeating pattern of these families you've been
> upstreaming lately.
>
Will do.
>> +
>> +static struct clk_regmap pwm_a_sel =
>> + AML_PWM_CLK_MUX(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 9);
>> +static struct clk_regmap pwm_a_div =
>> + AML_PWM_CLK_DIV(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 0);
>> +static struct clk_regmap pwm_a =
>> + AML_PWM_CLK_GATE(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 8);
>> +
>> +static struct clk_regmap pwm_b_sel =
>> + AML_PWM_CLK_MUX(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 25);
>> +static struct clk_regmap pwm_b_div =
>> + AML_PWM_CLK_DIV(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 16);
>> +static struct clk_regmap pwm_b =
>> + AML_PWM_CLK_GATE(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 24);
>> +
>> +static struct clk_regmap pwm_c_sel =
>> + AML_PWM_CLK_MUX(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 9);
>> +static struct clk_regmap pwm_c_div =
>> + AML_PWM_CLK_DIV(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 0);
>> +static struct clk_regmap pwm_c =
>> + AML_PWM_CLK_GATE(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 8);
>> +
>> +static struct clk_regmap pwm_d_sel =
>> + AML_PWM_CLK_MUX(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 25);
>> +static struct clk_regmap pwm_d_div =
>> + AML_PWM_CLK_DIV(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 16);
>> +static struct clk_regmap pwm_d =
>> + AML_PWM_CLK_GATE(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 24);
>> +
>> +static struct clk_regmap pwm_e_sel =
>> + AML_PWM_CLK_MUX(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 9);
>> +static struct clk_regmap pwm_e_div =
>> + AML_PWM_CLK_DIV(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 0);
>> +static struct clk_regmap pwm_e =
>> + AML_PWM_CLK_GATE(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 8);
>> +
>> +static struct clk_regmap pwm_f_sel =
>> + AML_PWM_CLK_MUX(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 25);
>> +static struct clk_regmap pwm_f_div =
>> + AML_PWM_CLK_DIV(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 16);
>> +static struct clk_regmap pwm_f =
>> + AML_PWM_CLK_GATE(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 24);
>> +
>> +static struct clk_regmap pwm_g_sel =
>> + AML_PWM_CLK_MUX(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 9);
>> +static struct clk_regmap pwm_g_div =
>> + AML_PWM_CLK_DIV(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 0);
>> +static struct clk_regmap pwm_g =
>> + AML_PWM_CLK_GATE(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 8);
>> +
>> +static struct clk_regmap pwm_h_sel =
>> + AML_PWM_CLK_MUX(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25);
>> +static struct clk_regmap pwm_h_div =
>> + AML_PWM_CLK_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16);
>> +static struct clk_regmap pwm_h =
>> + AML_PWM_CLK_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24);
>> +
>> +/* Channel 7 is gp1. */
>
> and ? if GP1 is RO, why can't you add it here ?
>
gp1_pll is a special clock for DSU, it is integrated into dsu_clk, we
don't want other modules to reference it.
My understanding is that gp1_pll should not be provided to the peripheral
clock tree, perhaps this is a redundant design.
>> +static const struct clk_parent_data spicc_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .fw_name = "sysclk" },
>> + { .fw_name = "fdiv4" },
>> + { .fw_name = "fdiv3" },
>> + { .fw_name = "fdiv2" },
>> + { .fw_name = "fdiv5" },
>> + { .fw_name = "fdiv7" }
>> +};
>> +
>> +static struct clk_regmap spicc_0_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .mask = 0x7,
>> + .shift = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_0_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = spicc_parent_data,
>> + .num_parents = ARRAY_SIZE(spicc_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap spicc_0_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .shift = 0,
>> + .width = 6,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_0_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &spicc_0_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap spicc_0 = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .bit_idx = 6,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_0",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &spicc_0_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap spicc_1_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .mask = 0x7,
>> + .shift = 23,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_1_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = spicc_parent_data,
>> + .num_parents = ARRAY_SIZE(spicc_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap spicc_1_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .shift = 16,
>> + .width = 6,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_1_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &spicc_1_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap spicc_1 = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>> + .bit_idx = 22,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "spicc_1",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &spicc_1_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static const struct clk_parent_data emmc_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .fw_name = "fdiv2" },
>> + { .fw_name = "fdiv3" },
>> + { .fw_name = "hifi" },
>> + { .fw_name = "fdiv2p5" },
>> + { .fw_name = "mpll2" },
>> + { .fw_name = "mpll3" },
>> + { .fw_name = "gp0" }
>> +};
>> +
>> +static struct clk_regmap sd_emmc_a_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
>> + .mask = 0x7,
>> + .shift = 9,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_a_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = emmc_parent_data,
>> + .num_parents = ARRAY_SIZE(emmc_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap sd_emmc_a_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
>> + .shift = 0,
>> + .width = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_a_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &sd_emmc_a_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap sd_emmc_a = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_SD_EMMC_CLK_CTRL,
>> + .bit_idx = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_a",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &sd_emmc_a_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap sd_emmc_c_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_NAND_CLK_CTRL,
>> + .mask = 0x7,
>> + .shift = 9,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_c_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = emmc_parent_data,
>> + .num_parents = ARRAY_SIZE(emmc_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap sd_emmc_c_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_NAND_CLK_CTRL,
>> + .shift = 0,
>> + .width = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_c_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &sd_emmc_c_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap sd_emmc_c = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_NAND_CLK_CTRL,
>> + .bit_idx = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "sd_emmc_c",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &sd_emmc_c_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap ts_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_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 = "oscin",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap ts = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_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 *[]) {
>> + &ts_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_fixed_factor eth_125m_div = {
>> + .mult = 1,
>> + .div = 8,
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "eth_125m_div",
>> + .ops = &clk_fixed_factor_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "fdiv2",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap eth_125m = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_ETH_CLK_CTRL,
>> + .bit_idx = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "eth_125m",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + ð_125m_div.hw
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap eth_rmii_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_ETH_CLK_CTRL,
>> + .shift = 0,
>> + .width = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "eth_rmii_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_data = &(const struct clk_parent_data) {
>> + .fw_name = "fdiv2",
>> + },
>> + .num_parents = 1,
>> + },
>> +};
>> +
>> +static struct clk_regmap eth_rmii = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_ETH_CLK_CTRL,
>> + .bit_idx = 8,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "eth_rmii",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + ð_rmii_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +/* Channel 6 is gp1. */
>
> same
>
gp1_pll is a special clock for DSU, it is integrated into dsu_clk, we
don't want other modules to reference it.
My understanding is that gp1_pll should not be provided to the peripheral
clock tree, perhaps this is a redundant design.
>> +static u32 dspa_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
>> +
>> +static const struct clk_parent_data dspa_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .fw_name = "fdiv2p5" },
>> + { .fw_name = "fdiv3" },
>> + { .fw_name = "rtc" },
>> + { .fw_name = "hifi" },
>> + { .fw_name = "fdiv4" },
>> + { .hw = &rtc_clk.hw }
>> +};
>> +
>> +static struct clk_regmap dspa_0_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .mask = 0x7,
>> + .shift = 10,
>> + .table = dspa_parent_table,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_0_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = dspa_parent_data,
>> + .num_parents = ARRAY_SIZE(dspa_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa_0_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .shift = 0,
>> + .width = 10,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_0_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &dspa_0_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa_0 = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .bit_idx = 13,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_0",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &dspa_0_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa_1_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .mask = 0x7,
>> + .shift = 26,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_1_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = dspa_parent_data,
>> + .num_parents = ARRAY_SIZE(dspa_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa_1_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .shift = 16,
>> + .width = 10,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_1_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &dspa_1_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa_1 = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .bit_idx = 29,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa_1",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &dspa_1_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>
> A word about SET_RATE_GATE ?
>
Look at the response to one of the questions below.
>> + },
>> +};
>> +
>> +static struct clk_regmap dspa = {
>> + .data = &(struct clk_regmap_mux_data){
>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>> + .mask = 0x1,
>> + .shift = 15,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "dspa",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &dspa_0.hw,
>> + &dspa_1.hw
>> + },
>> + .num_parents = 2,
>> + /*
>> + * NOTE: This level of mux is "no glitch mux", and mux_0
>> + * (here dspa_0) is not only the clock source for mux, but also
>> + * provides a working clock for "no glitch mux". "no glitch mux"
>> + * can be switched only when mux_0 has a clock input. Therefore,
>> + * add flag CLK_OPS_PARENT_ENABLE to ensure that mux_0 has clock
>> + * when "no glitch mux" works.
>> + */
>> + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
>
> Humm CLK_OPS_PARENT_ENABLE is not how we have handling glitch free mux
> so far. What changed ?
>
This is a hidden problem we have discovered in recent years, the
previous chip use is ping-pong switching "no-glitch-mux/glitch free"
have this problem. If mux_0 does not have a clock "no-glitch-mux", it
will not be able to switch channels, and I will organize and submit
patch to fix it later.
>> + },
>> +};
>> +
>> +/* Channel 6 is gp1. */
>> +static u32 nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
>> +
>> +static const struct clk_parent_data nna_parent_data[] = {
>> + { .fw_name = "oscin" },
>> + { .fw_name = "fdiv2p5" },
>> + { .fw_name = "fdiv4" },
>> + { .fw_name = "fdiv3" },
>> + { .fw_name = "fdiv5" },
>> + { .fw_name = "fdiv2" },
>> + { .fw_name = "hifi" }
>> +};
>> +
>> +static struct clk_regmap nna_core_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .mask = 0x7,
>> + .shift = 9,
>> + .table = nna_parent_table,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_core_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = nna_parent_data,
>> + .num_parents = ARRAY_SIZE(nna_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap nna_core_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .shift = 0,
>> + .width = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_core_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &nna_core_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap nna_core = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .bit_idx = 8,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_core",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &nna_core_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap nna_axi_sel = {
>> + .data = &(struct clk_regmap_mux_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .mask = 0x7,
>> + .shift = 25,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_axi_sel",
>> + .ops = &clk_regmap_mux_ops,
>> + .parent_data = nna_parent_data,
>> + .num_parents = ARRAY_SIZE(nna_parent_data),
>> + },
>> +};
>> +
>> +static struct clk_regmap nna_axi_div = {
>> + .data = &(struct clk_regmap_div_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .shift = 16,
>> + .width = 7,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_axi_div",
>> + .ops = &clk_regmap_divider_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &nna_axi_sel.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_regmap nna_axi = {
>> + .data = &(struct clk_regmap_gate_data) {
>> + .offset = CLKCTRL_NNA_CLK_CNTL,
>> + .bit_idx = 24,
>> + },
>> + .hw.init = &(struct clk_init_data) {
>> + .name = "nna_axi",
>> + .ops = &clk_regmap_gate_ops,
>> + .parent_hws = (const struct clk_hw *[]) {
>> + &nna_axi_div.hw
>> + },
>> + .num_parents = 1,
>> + .flags = CLK_SET_RATE_PARENT,
>> + },
>> +};
>> +
>> +static struct clk_hw *a5_periphs_hw_clks[] = {
>> + [CLKID_RTC_XTAL_CLKIN] = &rtc_xtal_clkin.hw,
>> + [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw,
>> + [CLKID_RTC_32K_MUX] = &rtc_32k_mux.hw,
>> + [CLKID_RTC_32K] = &rtc_32k.hw,
>> + [CLKID_RTC_CLK] = &rtc_clk.hw,
>> + [CLKID_SYS_RESET_CTRL] = &sys_reset_ctrl.hw,
>> + [CLKID_SYS_PWR_CTRL] = &sys_pwr_ctrl.hw,
>> + [CLKID_SYS_PAD_CTRL] = &sys_pad_ctrl.hw,
>> + [CLKID_SYS_CTRL] = &sys_ctrl.hw,
>> + [CLKID_SYS_TS_PLL] = &sys_ts_pll.hw,
>> + [CLKID_SYS_DEV_ARB] = &sys_dev_arb.hw,
>> + [CLKID_SYS_MMC_PCLK] = &sys_mmc_pclk.hw,
>> + [CLKID_SYS_MAILBOX] = &sys_mailbox.hw,
>> + [CLKID_SYS_CPU_CTRL] = &sys_cpu_ctrl.hw,
>> + [CLKID_SYS_JTAG_CTRL] = &sys_jtag_ctrl.hw,
>> + [CLKID_SYS_IR_CTRL] = &sys_ir_ctrl.hw,
>> + [CLKID_SYS_IRQ_CTRL] = &sys_irq_ctrl.hw,
>> + [CLKID_SYS_MSR_CLK] = &sys_msr_clk.hw,
>> + [CLKID_SYS_ROM] = &sys_rom.hw,
>> + [CLKID_SYS_CPU_ARB] = &sys_cpu_apb.hw,
>> + [CLKID_SYS_RSA] = &sys_rsa.hw,
>> + [CLKID_SYS_SAR_ADC] = &sys_sar_adc.hw,
>> + [CLKID_SYS_STARTUP] = &sys_startup.hw,
>> + [CLKID_SYS_SECURE] = &sys_secure.hw,
>> + [CLKID_SYS_SPIFC] = &sys_spifc.hw,
>> + [CLKID_SYS_DSPA] = &sys_dspa.hw,
>> + [CLKID_SYS_NNA] = &sys_nna.hw,
>> + [CLKID_SYS_ETH_MAC] = &sys_eth_mac.hw,
>> + [CLKID_SYS_GIC] = &sys_gic.hw,
>> + [CLKID_SYS_RAMA] = &sys_rama.hw,
>> + [CLKID_SYS_BIG_NIC] = &sys_big_nic.hw,
>> + [CLKID_SYS_RAMB] = &sys_ramb.hw,
>> + [CLKID_SYS_AUDIO_TOP] = &sys_audio_top.hw,
>> + [CLKID_SYS_AUDIO_VAD] = &sys_audio_vad.hw,
>> + [CLKID_SYS_USB] = &sys_usb.hw,
>> + [CLKID_SYS_SD_EMMC_A] = &sys_sd_emmc_a.hw,
>> + [CLKID_SYS_SD_EMMC_C] = &sys_sd_emmc_c.hw,
>> + [CLKID_SYS_PWM_AB] = &sys_pwm_ab.hw,
>> + [CLKID_SYS_PWM_CD] = &sys_pwm_cd.hw,
>> + [CLKID_SYS_PWM_EF] = &sys_pwm_ef.hw,
>> + [CLKID_SYS_PWM_GH] = &sys_pwm_gh.hw,
>> + [CLKID_SYS_SPICC_1] = &sys_spicc_1.hw,
>> + [CLKID_SYS_SPICC_0] = &sys_spicc_0.hw,
>> + [CLKID_SYS_UART_A] = &sys_uart_a.hw,
>> + [CLKID_SYS_UART_B] = &sys_uart_b.hw,
>> + [CLKID_SYS_UART_C] = &sys_uart_c.hw,
>> + [CLKID_SYS_UART_D] = &sys_uart_d.hw,
>> + [CLKID_SYS_UART_E] = &sys_uart_e.hw,
>> + [CLKID_SYS_I2C_M_A] = &sys_i2c_m_a.hw,
>> + [CLKID_SYS_I2C_M_B] = &sys_i2c_m_b.hw,
>> + [CLKID_SYS_I2C_M_C] = &sys_i2c_m_c.hw,
>> + [CLKID_SYS_I2C_M_D] = &sys_i2c_m_d.hw,
>> + [CLKID_SYS_RTC] = &sys_rtc.hw,
>> + [CLKID_AXI_AUDIO_VAD] = &axi_audio_vad.hw,
>> + [CLKID_AXI_AUDIO_TOP] = &axi_audio_top.hw,
>> + [CLKID_AXI_SYS_NIC] = &axi_sys_nic.hw,
>> + [CLKID_AXI_RAMB] = &axi_ramb.hw,
>> + [CLKID_AXI_RAMA] = &axi_rama.hw,
>> + [CLKID_AXI_CPU_DMC] = &axi_cpu_dmc.hw,
>> + [CLKID_AXI_NNA] = &axi_nna.hw,
>> + [CLKID_AXI_DEV1_DMC] = &axi_dev1_dmc.hw,
>> + [CLKID_AXI_DEV0_DMC] = &axi_dev0_dmc.hw,
>> + [CLKID_AXI_DSP_DMC] = &axi_dsp_dmc.hw,
>> + [CLKID_12_24M_IN] = &clk_12_24m_in.hw,
>> + [CLKID_12M_24M] = &clk_12_24m.hw,
>> + [CLKID_FCLK_25M_DIV] = &fclk_25m_div.hw,
>> + [CLKID_FCLK_25M] = &fclk_25m.hw,
>> + [CLKID_GEN_SEL] = &gen_sel.hw,
>> + [CLKID_GEN_DIV] = &gen_div.hw,
>> + [CLKID_GEN] = &gen.hw,
>> + [CLKID_SARADC_SEL] = &saradc_sel.hw,
>> + [CLKID_SARADC_DIV] = &saradc_div.hw,
>> + [CLKID_SARADC] = &saradc.hw,
>> + [CLKID_PWM_A_SEL] = &pwm_a_sel.hw,
>> + [CLKID_PWM_A_DIV] = &pwm_a_div.hw,
>> + [CLKID_PWM_A] = &pwm_a.hw,
>> + [CLKID_PWM_B_SEL] = &pwm_b_sel.hw,
>> + [CLKID_PWM_B_DIV] = &pwm_b_div.hw,
>> + [CLKID_PWM_B] = &pwm_b.hw,
>> + [CLKID_PWM_C_SEL] = &pwm_c_sel.hw,
>> + [CLKID_PWM_C_DIV] = &pwm_c_div.hw,
>> + [CLKID_PWM_C] = &pwm_c.hw,
>> + [CLKID_PWM_D_SEL] = &pwm_d_sel.hw,
>> + [CLKID_PWM_D_DIV] = &pwm_d_div.hw,
>> + [CLKID_PWM_D] = &pwm_d.hw,
>> + [CLKID_PWM_E_SEL] = &pwm_e_sel.hw,
>> + [CLKID_PWM_E_DIV] = &pwm_e_div.hw,
>> + [CLKID_PWM_E] = &pwm_e.hw,
>> + [CLKID_PWM_F_SEL] = &pwm_f_sel.hw,
>> + [CLKID_PWM_F_DIV] = &pwm_f_div.hw,
>> + [CLKID_PWM_F] = &pwm_f.hw,
>> + [CLKID_PWM_G_SEL] = &pwm_g_sel.hw,
>> + [CLKID_PWM_G_DIV] = &pwm_g_div.hw,
>> + [CLKID_PWM_G] = &pwm_g.hw,
>> + [CLKID_PWM_H_SEL] = &pwm_h_sel.hw,
>> + [CLKID_PWM_H_DIV] = &pwm_h_div.hw,
>> + [CLKID_PWM_H] = &pwm_h.hw,
>> + [CLKID_SPICC_0_SEL] = &spicc_0_sel.hw,
>> + [CLKID_SPICC_0_DIV] = &spicc_0_div.hw,
>> + [CLKID_SPICC_0] = &spicc_0.hw,
>> + [CLKID_SPICC_1_SEL] = &spicc_1_sel.hw,
>> + [CLKID_SPICC_1_DIV] = &spicc_1_div.hw,
>> + [CLKID_SPICC_1] = &spicc_1.hw,
>> + [CLKID_SD_EMMC_A_SEL] = &sd_emmc_a_sel.hw,
>> + [CLKID_SD_EMMC_A_DIV] = &sd_emmc_a_div.hw,
>> + [CLKID_SD_EMMC_A] = &sd_emmc_a.hw,
>> + [CLKID_SD_EMMC_C_SEL] = &sd_emmc_c_sel.hw,
>> + [CLKID_SD_EMMC_C_DIV] = &sd_emmc_c_div.hw,
>> + [CLKID_SD_EMMC_C] = &sd_emmc_c.hw,
>> + [CLKID_TS_DIV] = &ts_div.hw,
>> + [CLKID_TS] = &ts.hw,
>> + [CLKID_ETH_125M_DIV] = ð_125m_div.hw,
>> + [CLKID_ETH_125M] = ð_125m.hw,
>> + [CLKID_ETH_RMII_DIV] = ð_rmii_div.hw,
>> + [CLKID_ETH_RMII] = ð_rmii.hw,
>> + [CLKID_DSPA_0_SEL] = &dspa_0_sel.hw,
>> + [CLKID_DSPA_0_DIV] = &dspa_0_div.hw,
>> + [CLKID_DSPA_0] = &dspa_0.hw,
>> + [CLKID_DSPA_1_SEL] = &dspa_1_sel.hw,
>> + [CLKID_DSPA_1_DIV] = &dspa_1_div.hw,
>> + [CLKID_DSPA_1] = &dspa_1.hw,
>> + [CLKID_DSPA] = &dspa.hw,
>> + [CLKID_NNA_CORE_SEL] = &nna_core_sel.hw,
>> + [CLKID_NNA_CORE_DIV] = &nna_core_div.hw,
>> + [CLKID_NNA_CORE] = &nna_core.hw,
>> + [CLKID_NNA_AXI_SEL] = &nna_axi_sel.hw,
>> + [CLKID_NNA_AXI_DIV] = &nna_axi_div.hw,
>> + [CLKID_NNA_AXI] = &nna_axi.hw,
>> +};
>> +
>> +/* Convenience table to populate regmap in .probe */
>> +static struct clk_regmap *const a5_periphs_clk_regmaps[] = {
>> + &rtc_xtal_clkin,
>> + &rtc_32k_div,
>> + &rtc_32k_mux,
>> + &rtc_32k,
>> + &rtc_clk,
>> + &sys_reset_ctrl,
>> + &sys_pwr_ctrl,
>> + &sys_pad_ctrl,
>> + &sys_ctrl,
>> + &sys_ts_pll,
>> + &sys_dev_arb,
>> + &sys_mmc_pclk,
>> + &sys_mailbox,
>> + &sys_cpu_ctrl,
>> + &sys_jtag_ctrl,
>> + &sys_ir_ctrl,
>> + &sys_irq_ctrl,
>> + &sys_msr_clk,
>> + &sys_rom,
>> + &sys_cpu_apb,
>> + &sys_rsa,
>> + &sys_sar_adc,
>> + &sys_startup,
>> + &sys_secure,
>> + &sys_spifc,
>> + &sys_dspa,
>> + &sys_nna,
>> + &sys_eth_mac,
>> + &sys_gic,
>> + &sys_rama,
>> + &sys_big_nic,
>> + &sys_ramb,
>> + &sys_audio_top,
>> + &sys_audio_vad,
>> + &sys_usb,
>> + &sys_sd_emmc_a,
>> + &sys_sd_emmc_c,
>> + &sys_pwm_ab,
>> + &sys_pwm_cd,
>> + &sys_pwm_ef,
>> + &sys_pwm_gh,
>> + &sys_spicc_1,
>> + &sys_spicc_0,
>> + &sys_uart_a,
>> + &sys_uart_b,
>> + &sys_uart_c,
>> + &sys_uart_d,
>> + &sys_uart_e,
>> + &sys_i2c_m_a,
>> + &sys_i2c_m_b,
>> + &sys_i2c_m_c,
>> + &sys_i2c_m_d,
>> + &sys_rtc,
>> + &axi_audio_vad,
>> + &axi_audio_top,
>> + &axi_sys_nic,
>> + &axi_ramb,
>> + &axi_rama,
>> + &axi_cpu_dmc,
>> + &axi_nna,
>> + &axi_dev1_dmc,
>> + &axi_dev0_dmc,
>> + &axi_dsp_dmc,
>> + &clk_12_24m_in,
>> + &clk_12_24m,
>> + &fclk_25m_div,
>> + &fclk_25m,
>> + &gen_sel,
>> + &gen_div,
>> + &gen,
>> + &saradc_sel,
>> + &saradc_div,
>> + &saradc,
>> + &pwm_a_sel,
>> + &pwm_a_div,
>> + &pwm_a,
>> + &pwm_b_sel,
>> + &pwm_b_div,
>> + &pwm_b,
>> + &pwm_c_sel,
>> + &pwm_c_div,
>> + &pwm_c,
>> + &pwm_d_sel,
>> + &pwm_d_div,
>> + &pwm_d,
>> + &pwm_e_sel,
>> + &pwm_e_div,
>> + &pwm_e,
>> + &pwm_f_sel,
>> + &pwm_f_div,
>> + &pwm_f,
>> + &pwm_g_sel,
>> + &pwm_g_div,
>> + &pwm_g,
>> + &pwm_h_sel,
>> + &pwm_h_div,
>> + &pwm_h,
>> + &spicc_0_sel,
>> + &spicc_0_div,
>> + &spicc_0,
>> + &spicc_1_sel,
>> + &spicc_1_div,
>> + &spicc_1,
>> + &sd_emmc_a_sel,
>> + &sd_emmc_a_div,
>> + &sd_emmc_a,
>> + &sd_emmc_c_sel,
>> + &sd_emmc_c_div,
>> + &sd_emmc_c,
>> + &ts_div,
>> + &ts,
>> + ð_125m,
>> + ð_rmii_div,
>> + ð_rmii,
>> + &dspa_0_sel,
>> + &dspa_0_div,
>> + &dspa_0,
>> + &dspa_1_sel,
>> + &dspa_1_div,
>> + &dspa_1,
>> + &dspa,
>> + &nna_core_sel,
>> + &nna_core_div,
>> + &nna_core,
>> + &nna_axi_sel,
>> + &nna_axi_div,
>> + &nna_axi
>> +};
>> +
>> +static const struct regmap_config clkc_regmap_config = {
>> + .reg_bits = 32,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> + .max_register = CLKCTRL_NNA_CLK_CNTL,
>> +};
>> +
>> +static struct meson_clk_hw_data a5_periphs_clks = {
>> + .hws = a5_periphs_hw_clks,
>> + .num = ARRAY_SIZE(a5_periphs_hw_clks),
>> +};
>> +
>> +static int aml_a5_peripherals_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct regmap *regmap;
>> + void __iomem *base;
>> + int clkid, ret, i;
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
>> + if (IS_ERR(regmap))
>> + return PTR_ERR(regmap);
>> +
>> + /* Populate regmap for the regmap backed clocks */
>> + for (i = 0; i < ARRAY_SIZE(a5_periphs_clk_regmaps); i++)
>> + a5_periphs_clk_regmaps[i]->map = regmap;
>> +
>> + for (clkid = 0; clkid < a5_periphs_clks.num; clkid++) {
>> + /* array might be sparse */
>> + if (!a5_periphs_clks.hws[clkid])
>> + continue;
>> +
>> + ret = devm_clk_hw_register(dev, a5_periphs_clks.hws[clkid]);
>> + if (ret) {
>> + dev_err(dev, "Clock registration failed\n");
>> + return ret;
>> + }
>> + }
>> +
>> + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
>> + &a5_periphs_clks);
>> +}
>> +
>> +static const struct of_device_id a5_peripherals_clkc_match_table[] = {
>> + {
>> + .compatible = "amlogic,a5-peripherals-clkc",
>> + },
>> + { /* sentinel */ }
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, a5_peripherals_clkc_match_table);
>> +
>> +static struct platform_driver a5_peripherals_driver = {
>> + .probe = aml_a5_peripherals_probe,
>> + .driver = {
>> + .name = "a5-peripherals-clkc",
>> + .of_match_table = a5_peripherals_clkc_match_table,
>> + },
>> +};
>> +module_platform_driver(a5_peripherals_driver);
>> +
>> +MODULE_DESCRIPTION("Amlogic A5 Peripherals Clock Controller driver");
>> +MODULE_AUTHOR("Chuan Liu <chuan.liu@amlogic.com>");
>> +MODULE_LICENSE("GPL");
>
> --
> Jerome
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock
2024-09-29 8:17 ` Xianwei Zhao
@ 2024-09-30 9:41 ` Jerome Brunet
2024-10-12 5:43 ` Xianwei Zhao
0 siblings, 1 reply; 17+ messages in thread
From: Jerome Brunet @ 2024-09-30 9:41 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Xianwei Zhao via B4 Relay, Neil Armstrong, Michael Turquette,
Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chuan Liu, Kevin Hilman, Martin Blumenstingl, linux-amlogic,
linux-clk, devicetree, linux-kernel, linux-arm-kernel
On Sun 29 Sep 2024 at 16:17, Xianwei Zhao <xianwei.zhao@amlogic.com> wrote:
> Hi Jerome,
> Thanks for your reply.
>
> On 2024/9/24 22:45, Jerome Brunet wrote:
>> [ EXTERNAL EMAIL ]
>> On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay
>> <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
>>
>>> From: Chuan Liu <chuan.liu@amlogic.com>
>>>
>>> Add the PLL clock controller driver for the Amlogic A5 SoC family.
>>>
>>> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
>>> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
>>> ---
>>> drivers/clk/meson/Kconfig | 14 ++
>>> drivers/clk/meson/Makefile | 1 +
>>> drivers/clk/meson/a5-pll.c | 553 +++++++++++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 568 insertions(+)
>>>
>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>> index 78f648c9c97d..2a713276e46c 100644
>>> --- a/drivers/clk/meson/Kconfig
>>> +++ b/drivers/clk/meson/Kconfig
>>> @@ -132,6 +132,20 @@ config COMMON_CLK_A1_PERIPHERALS
>>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>>> controller to work.
>>>
>>> +config COMMON_CLK_A5_PLL
>>> + tristate "Amlogic A5 PLL clock controller"
>>> + depends on ARM64
>>> + default y
>>> + imply ARM_SCMI_PROTOCOL
>> don't think this is needed, same as c3
>>
>
> Will delete it in the next version.
Ideally, please trim your replies. This avoid the need for me to dig in
such long patch and find whatever it is that you replied.
That means, remove text that is not necessary to the reply, leaving the
necessary context for the discussion.
Also, if it is just to say that 'you will do it', a reply is no
necessary. Just do it, it will be fine. Reply if you have further
questions, remarks or do not agree.
>
>>> + imply COMMON_CLK_SCMI
>>> + select COMMON_CLK_MESON_REGMAP
>>> + select COMMON_CLK_MESON_PLL
>>> + select COMMON_CLK_MESON_CLKC_UTILS
>>> + help
>>> + Support for the PLL clock controller on Amlogic AV40x device, AKA A5.
>>> + Say Y if you want the board to work, because PLLs are the parent
>>> + of most peripherals.
>>> +
>>> config COMMON_CLK_C3_PLL
>>> tristate "Amlogic C3 PLL clock controller"
>>> depends on ARM64
>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>> index bc56a47931c1..fc4b8a723145 100644
>>> --- a/drivers/clk/meson/Makefile
>>> +++ b/drivers/clk/meson/Makefile
>>> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>>> +obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
>>> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>>> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>> diff --git a/drivers/clk/meson/a5-pll.c b/drivers/clk/meson/a5-pll.c
>>> new file mode 100644
>>> index 000000000000..d96ed72ef8d4
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a5-pll.c
>>> @@ -0,0 +1,553 @@
[...]
>>> +static struct clk_regmap gp0_pll = {
>>> + .data = &(struct clk_regmap_div_data) {
>>> + .offset = ANACTRL_GP0PLL_CTRL0,
>>> + .shift = 16,
>>> + .width = 3,
>>> + .table = gp0_pll_od_table,
>>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "gp0_pll",
>>> + .ops = &clk_regmap_divider_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &gp0_pll_dco.hw
>>> + },
>>> + .num_parents = 1,
>>> + .flags = CLK_SET_RATE_PARENT,
>>> + },
>>> +};
>>> +
>>> +static const struct reg_sequence hifi_init_regs[] = {
>>> + { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0X08000000 },
>> What is bit you are flipping in CTRL0 ? it is suspicious
>>
>
> Yes, CTRL0 and CTRL1 are not necessary here and will be removed in the
> next version.
That does not really answer my question, does it ?
>
>>> + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00000000 },
>>> + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
>>> + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a295c00 },
>>> + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
>>> + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
>>> + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x54540000 }
>>> +};
>>> +
>>> +static const struct pll_mult_range hifi_pll_mult_range = {
>>> + .min = 125,
>>> + .max = 250,
>>> +};
>>> +
>>> +static struct clk_regmap hifi_pll_dco = {
>>> + .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,
>>> + },
>>> + .frac = {
>>> + .reg_off = ANACTRL_HIFIPLL_CTRL1,
>>> + .shift = 0,
>>> + .width = 17,
>>> + },
>>> + .n = {
>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> + .shift = 10,
>>> + .width = 5,
>>> + },
>>> + .l = {
>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> + .shift = 31,
>>> + .width = 1,
>>> + },
>>> + .rst = {
>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>> + .shift = 29,
>>> + .width = 1,
>>> + },
>>> + .range = &hifi_pll_mult_range,
>>> + .init_regs = hifi_init_regs,
>>> + .init_count = ARRAY_SIZE(hifi_init_regs),
>>> + .frac_max = 100000,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "hifi_pll_dco",
>>> + .ops = &meson_clk_pll_ops,
>>> + .parent_data = &(const struct clk_parent_data) {
>>> + .fw_name = "xtal_24m",
>>> + },
>>> + .num_parents = 1,
>>> + },
>>> +};
>>> +
>>> +/* The maximum frequency divider supports is 16, not 128(2^7) */
>>> +static const struct clk_div_table hifi_pll_od_table[] = {
>>> + { 0, 1 },
>>> + { 1, 2 },
>>> + { 2, 4 },
>>> + { 3, 8 },
>> Why don't you ajust the mask then ? Looks like a POW_OF_2 basic
>> dividider to me.
>>
>
> The maximum frequency division value above the design document is 8,
> such as the configuration 4/5/6... The actual frequency division value
> is still 8, so this table is defined, why there is this restriction in
> detail I am not clear about.
>
> Will add these comment ot describe it.
I'm not asking you to add a comment.
With your explanation, my comment still stands.
>
>>> + { /* sentinel */ }
>>> +};
>>> +
>>> +static struct clk_regmap hifi_pll = {
>>> + .data = &(struct clk_regmap_div_data) {
>>> + .offset = ANACTRL_HIFIPLL_CTRL0,
>>> + .shift = 16,
>>> + .width = 3,
>>> + .table = hifi_pll_od_table,
>>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "hifi_pll",
>>> + .ops = &clk_regmap_divider_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &hifi_pll_dco.hw
>>> + },
>>> + .num_parents = 1,
>>> + .flags = CLK_SET_RATE_PARENT,
>>> + },
>>> +};
>>> +
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver
2024-09-29 8:44 ` Xianwei Zhao
@ 2024-09-30 10:16 ` Jerome Brunet
2024-10-12 5:50 ` Xianwei Zhao
0 siblings, 1 reply; 17+ messages in thread
From: Jerome Brunet @ 2024-09-30 10:16 UTC (permalink / raw)
To: Xianwei Zhao
Cc: Xianwei Zhao via B4 Relay, Neil Armstrong, Michael Turquette,
Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chuan Liu, Kevin Hilman, Martin Blumenstingl, linux-amlogic,
linux-clk, devicetree, linux-kernel, linux-arm-kernel
On Sun 29 Sep 2024 at 16:44, Xianwei Zhao <xianwei.zhao@amlogic.com> wrote:
[...]
>>> +static A4_SYS_GATE(sys_eth_mac, CLKCTRL_SYS_CLK_EN0_REG0, 26, 0);
>>> +
>>> +/*
>>> + * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller).
>>> + * After clock is disabled, The GIC cannot work properly. At present, the driver
>>> + * used by our GIC is the public driver in kernel, and there is no management
>>> + * clock in the driver.
>>> + */
>>> +static A4_SYS_GATE(sys_gic, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL);
>> The GIC has a driver. If it needs clock, maybe it should request it and
>> enable it, maybe as optional.
>>
>
> This has been explained in C3. GIC is a public driver that does not
> reference clock, so you suggest setting it as CRITICAL and adding the
> "FIXME" annotation.
Yes indeed ... and at some point, it is expected something will be done
a actually fix the situation ... not just pile-up FIXME comments.
Adding a clock to a driver that should have one seems doable.
>
>>> +static A4_SYS_GATE(sys_rama, CLKCTRL_SYS_CLK_EN0_REG0, 28, 0);
>>> +
>>> +/*
>>> + * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network
>>> + * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC,
>>> + * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the
>>> + * system. After clock is disabled, The NIC cannot work.
>>> + */
>> This comment looks like a clock that should be passed as ressource to a
>> bus or power-domain to be properly manage. This is a pattern that keeps
>> on repeating. I will not block you on it this time around but I strong
>> suggest you fix up the situation on the related platform. Next time
>> around, the reason won't be a valid one.
>>
>
> There are too many modules associated with this clock... The most important
> is the inclusion of some system-level modules that are not managed by the
> driver in the kernel and cannot close their clocks, perhaps it is not
> appropriate to describe it here.
>
> In the next version I moved it to scmi-clk for management?
No. The number of module associated with a clock should not be a
concern and SCMI should not be a 'Hide all the things I don't want to do
in linux things'.
You've got a bus that needs a clocks. There are possibilities associate
a clock with bus in DT, either directly or through power-domains. Please
do it correctly.
>
>>> +static A4_SYS_GATE(sys_big_nic, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL);
>>> +static A4_SYS_GATE(sys_ramb, CLKCTRL_SYS_CLK_EN0_REG0, 30, 0);
>>> +static A4_SYS_GATE(sys_audio_top, CLKCTRL_SYS_CLK_EN0_REG1, 0, 0);
>>> +static A4_SYS_GATE(sys_audio_vad, CLKCTRL_SYS_CLK_EN0_REG1, 1, 0);
>>> +static A4_SYS_GATE(sys_usb, CLKCTRL_SYS_CLK_EN0_REG1, 2, 0);
>>> +static A4_SYS_GATE(sys_sd_emmc_a, CLKCTRL_SYS_CLK_EN0_REG1, 3, 0);
>>> +static A4_SYS_GATE(sys_sd_emmc_c, CLKCTRL_SYS_CLK_EN0_REG1, 4, 0);
>>> +static A4_SYS_GATE(sys_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG1, 5, 0);
>>> +static A4_SYS_GATE(sys_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG1, 6, 0);
>>> +static A4_SYS_GATE(sys_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG1, 7, 0);
>>> +static A4_SYS_GATE(sys_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG1, 8, 0);
>>> +static A4_SYS_GATE(sys_spicc_1, CLKCTRL_SYS_CLK_EN0_REG1, 9, 0);
>>> +static A4_SYS_GATE(sys_spicc_0, CLKCTRL_SYS_CLK_EN0_REG1, 10, 0);
>>> +static A4_SYS_GATE(sys_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 11, 0);
>>> +static A4_SYS_GATE(sys_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 12, 0);
>>> +static A4_SYS_GATE(sys_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 13, 0);
>>> +static A4_SYS_GATE(sys_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 14, 0);
>>> +static A4_SYS_GATE(sys_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 15, 0);
>>> +static A4_SYS_GATE(sys_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 16, 0);
>>> +static A4_SYS_GATE(sys_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 17, 0);
>>> +static A4_SYS_GATE(sys_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG1, 18, 0);
>>> +static A4_SYS_GATE(sys_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG1, 19, 0);
>>> +static A4_SYS_GATE(sys_rtc, CLKCTRL_SYS_CLK_EN0_REG1, 21, 0);
>>> +
>>> +#define A4_AXI_GATE(_name, _reg, _bit, _flags) \
>>> + A4_CLK_GATE(_name, _reg, _bit, axiclk, \
>>> + &clk_regmap_gate_ops, _flags)
>>> +
>>> +static A4_AXI_GATE(axi_audio_vad, CLKCTRL_AXI_CLK_EN0, 0, 0);
>>> +static A4_AXI_GATE(axi_audio_top, CLKCTRL_AXI_CLK_EN0, 1, 0);
>>> +
>>> +/*
>>> + * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After
>>> + * clock is disabled, The NIC cannot work.
>>> + */
>>> +static A4_AXI_GATE(axi_sys_nic, CLKCTRL_AXI_CLK_EN0, 2, CLK_IS_CRITICAL);
>>> +static A4_AXI_GATE(axi_ramb, CLKCTRL_AXI_CLK_EN0, 5, 0);
>>> +static A4_AXI_GATE(axi_rama, CLKCTRL_AXI_CLK_EN0, 6, 0);
>>> +
>>> +/*
>>> + * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses
>>> + * the DDR. After clock is disabled, The CPU will not have access to the DDR.
>>> + */
>>> +static A4_AXI_GATE(axi_cpu_dmc, CLKCTRL_AXI_CLK_EN0, 7, CLK_IS_CRITICAL);
>>> +static A4_AXI_GATE(axi_nna, CLKCTRL_AXI_CLK_EN0, 12, 0);
>>> +
>>> +/*
>>> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
>>> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
>>> + */
>> Same.
>>
>
> These normal peripheral drivers manage the clock without a problem.
>
>>> +static A4_AXI_GATE(axi_dev1_dmc, CLKCTRL_AXI_CLK_EN0, 13, 0);
>>> +
>>> +/*
>>> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
>>> + * to access the AXI bus of the DDR.
>>> + */
>>> +static A4_AXI_GATE(axi_dev0_dmc, CLKCTRL_AXI_CLK_EN0, 14, 0);
>>> +static A4_AXI_GATE(axi_dsp_dmc, CLKCTRL_AXI_CLK_EN0, 15, 0);
>>> +
>>> +static struct clk_regmap clk_12_24m_in = {
>>> + .data = &(struct clk_regmap_gate_data) {
>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>> + .bit_idx = 11,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "clk_12_24m_in",
>>> + .ops = &clk_regmap_gate_ops,
>>> + .parent_data = &(const struct clk_parent_data) {
>>> + .fw_name = "xtal_24m",
>>> + },
>>> + .num_parents = 1,
>>> + },
>>> +};
>>> +
>>> +static struct clk_regmap clk_12_24m = {
>>> + .data = &(struct clk_regmap_div_data) {
>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>> + .shift = 10,
>>> + .width = 1,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "clk_12_24m",
>>> + .ops = &clk_regmap_divider_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &clk_12_24m_in.hw
>>> + },
>>> + .num_parents = 1,
>>> + },
>>> +};
>>> +
>>> +/* FIXME: set value 0 will div by 2 like value 1 */
>> Again, it is fine when it happens once, like the c3.
>> When the pattern starts repeating, it is time to do something about it.
>>
>
> The corresponding suggestions have been made to the hardware designer, but
> now the designed chip cannot be repaired.
Not asking to fix the HW (although that would be nice if you could)
The HW is what it is. The SW needs fixing. That you can do.
>
>>> +static struct clk_regmap fclk_25m_div = {
>>> + .data = &(struct clk_regmap_div_data) {
>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>> + .shift = 0,
>>> + .width = 8,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "fclk_25m_div",
>>> + .ops = &clk_regmap_divider_ops,
>>> + .parent_data = &(const struct clk_parent_data) {
>>> + .fw_name = "fix",
>>> + },
>>> + .num_parents = 1,
>>> + },
>>> +};
>>> +
>>> +static struct clk_regmap fclk_25m = {
>>> + .data = &(struct clk_regmap_gate_data) {
>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>> + .bit_idx = 12,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "fclk_25m",
>>> + .ops = &clk_regmap_gate_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &fclk_25m_div.hw
>>> + },
>>> + .num_parents = 1,
>>> + .flags = CLK_SET_RATE_PARENT,
>>> + },
>>> +};
>>> +
>>> +/*
>>> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk)
>>> + * is manged by clock measures module. Their hardware are out of clock tree.
>> Yet, they exist and should be part of the bindings since they are
>> obviously input to this clock.
>>
>
> Will add it to bindings, as optional input clock source.
>
>>> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
>>> + *
>>> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
>>> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug purposes.
>>> + */
>>> +static u32 gen_parent_table[] = { 0, 1, 2, 6, 7, 17, 19, 20, 21, 22, 23, 24, 25,
>>> + 26, 27, 28};
>>> +
>>> +static const struct clk_parent_data gen_parent_data[] = {
>>> + { .fw_name = "oscin" },
>>> + { .hw = &rtc_clk.hw },
>>> + { .fw_name = "sysplldiv16" },
>>> + { .fw_name = "gp1" },
>>> + { .fw_name = "hifi" },
>>> + { .fw_name = "cpudiv16" },
>>> + { .fw_name = "fdiv2" },
>>> + { .fw_name = "fdiv2p5" },
>>> + { .fw_name = "fdiv3" },
>>> + { .fw_name = "fdiv4" },
>>> + { .fw_name = "fdiv5" },
>>> + { .fw_name = "fdiv7" },
>>> + { .fw_name = "mpll0" },
>>> + { .fw_name = "mpll1" },
>>> + { .fw_name = "mpll2" },
>>> + { .fw_name = "mpll3" }
>>> +};
[...]
>>> +
>>> +static struct clk_regmap pwm_h_sel =
>>> + AML_PWM_CLK_MUX(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25);
>>> +static struct clk_regmap pwm_h_div =
>>> + AML_PWM_CLK_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16);
>>> +static struct clk_regmap pwm_h =
>>> + AML_PWM_CLK_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24);
>>> +
>>> +/* Channel 7 is gp1. */
>> and ? if GP1 is RO, why can't you add it here ?
>>
>
> gp1_pll is a special clock for DSU, it is integrated into dsu_clk, we
> don't want other modules to reference it.
>
> My understanding is that gp1_pll should not be provided to the peripheral
> clock tree, perhaps this is a redundant design.
Then /* Channel 7 is gp1 which is reserved for DSU */
Note that if GP1 is actually RO and DSU does not change the rate at
runtime through other means, then listing GP1 here should not be a
problem, spi would just be user of an available PLL.
>
>>> +static const struct clk_parent_data spicc_parent_data[] = {
>>> + { .fw_name = "oscin" },
>>> + { .fw_name = "sysclk" },
>>> + { .fw_name = "fdiv4" },
>>> + { .fw_name = "fdiv3" },
>>> + { .fw_name = "fdiv2" },
>>> + { .fw_name = "fdiv5" },
>>> + { .fw_name = "fdiv7" }
>>> +};
>>> +
>>> +static struct clk_regmap spicc_0_sel = {
>>> + .data = &(struct clk_regmap_mux_data) {
>>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>>> + .mask = 0x7,
>>> + .shift = 7,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "spicc_0_sel",
>>> + .ops = &clk_regmap_mux_ops,
>>> + .parent_data = spicc_parent_data,
>>> + .num_parents = ARRAY_SIZE(spicc_parent_data),
>>> + },
>>> +};
[...]
>>> +
>>> +static struct clk_regmap dspa_1 = {
>>> + .data = &(struct clk_regmap_gate_data) {
>>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>>> + .bit_idx = 29,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "dspa_1",
>>> + .ops = &clk_regmap_gate_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &dspa_1_div.hw
>>> + },
>>> + .num_parents = 1,
>>> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>> A word about SET_RATE_GATE ?
>>
>
> Look at the response to one of the questions below.
Still a word ? your comment below does justify this flag clearly.
>
>>> + },
>>> +};
>>> +
>>> +static struct clk_regmap dspa = {
>>> + .data = &(struct clk_regmap_mux_data){
>>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>>> + .mask = 0x1,
>>> + .shift = 15,
>>> + },
>>> + .hw.init = &(struct clk_init_data) {
>>> + .name = "dspa",
>>> + .ops = &clk_regmap_mux_ops,
>>> + .parent_hws = (const struct clk_hw *[]) {
>>> + &dspa_0.hw,
>>> + &dspa_1.hw
>>> + },
>>> + .num_parents = 2,
>>> + /*
>>> + * NOTE: This level of mux is "no glitch mux", and mux_0
>>> + * (here dspa_0) is not only the clock source for mux, but also
>>> + * provides a working clock for "no glitch mux". "no glitch mux"
>>> + * can be switched only when mux_0 has a clock input. Therefore,
>>> + * add flag CLK_OPS_PARENT_ENABLE to ensure that mux_0 has clock
>>> + * when "no glitch mux" works.
>>> + */
>>> + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
>> Humm CLK_OPS_PARENT_ENABLE is not how we have handling glitch free mux
>> so far. What changed ?
>>
>
> This is a hidden problem we have discovered in recent years, the previous
> chip use is ping-pong switching "no-glitch-mux/glitch free" have this
> problem. If mux_0 does not have a clock "no-glitch-mux", it will not be
> able to switch channels, and I will organize and submit patch to fix it
> later.
The NOTE comment and what the code does are not aligned.
* Your comment says that input #0 must be enabled for the mux to work
* The flag ensure that parent is enabled before switching to it. There
is nothing specific about input #0
>
>>> + },
>>> +};
>>> +
>>> +/* Channel 6 is gp1. */
>>> +static u32 nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
>>> +
>>> +static const struct clk_parent_data nna_parent_data[] = {
>>> + { .fw_name = "oscin" },
>>> + { .fw_name = "fdiv2p5" },
>>> + { .fw_name = "fdiv4" },
>>> + { .fw_name = "fdiv3" },
>>> + { .fw_name = "fdiv5" },
>>> + { .fw_name = "fdiv2" },
>>> + { .fw_name = "hifi" }
>>> +};
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock
2024-09-30 9:41 ` Jerome Brunet
@ 2024-10-12 5:43 ` Xianwei Zhao
0 siblings, 0 replies; 17+ messages in thread
From: Xianwei Zhao @ 2024-10-12 5:43 UTC (permalink / raw)
To: Jerome Brunet
Cc: Xianwei Zhao via B4 Relay, Neil Armstrong, Michael Turquette,
Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chuan Liu, Kevin Hilman, Martin Blumenstingl, linux-amlogic,
linux-clk, devicetree, linux-kernel, linux-arm-kernel
Hi Jerome,
Thanks for your reply.
On 2024/9/30 17:41, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
> On Sun 29 Sep 2024 at 16:17, Xianwei Zhao <xianwei.zhao@amlogic.com> wrote:
>
>> Hi Jerome,
>> Thanks for your reply.
>>
>> On 2024/9/24 22:45, Jerome Brunet wrote:
>>> [ EXTERNAL EMAIL ]
>>> On Sat 14 Sep 2024 at 13:25, Xianwei Zhao via B4 Relay
>>> <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote:
>>>
>>>> From: Chuan Liu <chuan.liu@amlogic.com>
>>>>
>>>> Add the PLL clock controller driver for the Amlogic A5 SoC family.
>>>>
>>>> Signed-off-by: Chuan Liu <chuan.liu@amlogic.com>
>>>> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
>>>> ---
>>>> drivers/clk/meson/Kconfig | 14 ++
>>>> drivers/clk/meson/Makefile | 1 +
>>>> drivers/clk/meson/a5-pll.c | 553 +++++++++++++++++++++++++++++++++++++++++++++
>>>> 3 files changed, 568 insertions(+)
>>>>
>>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>>> index 78f648c9c97d..2a713276e46c 100644
>>>> --- a/drivers/clk/meson/Kconfig
>>>> +++ b/drivers/clk/meson/Kconfig
>>>> @@ -132,6 +132,20 @@ config COMMON_CLK_A1_PERIPHERALS
>>>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>>>> controller to work.
>>>>
>>>> +config COMMON_CLK_A5_PLL
>>>> + tristate "Amlogic A5 PLL clock controller"
>>>> + depends on ARM64
>>>> + default y
>>>> + imply ARM_SCMI_PROTOCOL
>>> don't think this is needed, same as c3
>>>
>>
>> Will delete it in the next version.
>
>
> Ideally, please trim your replies. This avoid the need for me to dig in
> such long patch and find whatever it is that you replied.
>
> That means, remove text that is not necessary to the reply, leaving the
> necessary context for the discussion.
>
> Also, if it is just to say that 'you will do it', a reply is no
> necessary. Just do it, it will be fine. Reply if you have further
> questions, remarks or do not agree.
>
>>
>>>> + imply COMMON_CLK_SCMI
>>>> + select COMMON_CLK_MESON_REGMAP
>>>> + select COMMON_CLK_MESON_PLL
>>>> + select COMMON_CLK_MESON_CLKC_UTILS
>>>> + help
>>>> + Support for the PLL clock controller on Amlogic AV40x device, AKA A5.
>>>> + Say Y if you want the board to work, because PLLs are the parent
>>>> + of most peripherals.
>>>> +
>>>> config COMMON_CLK_C3_PLL
>>>> tristate "Amlogic C3 PLL clock controller"
>>>> depends on ARM64
>>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>>> index bc56a47931c1..fc4b8a723145 100644
>>>> --- a/drivers/clk/meson/Makefile
>>>> +++ b/drivers/clk/meson/Makefile
>>>> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>>>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>>>> +obj-$(CONFIG_COMMON_CLK_A5_PLL) += a5-pll.o
>>>> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>>>> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>>>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>>> diff --git a/drivers/clk/meson/a5-pll.c b/drivers/clk/meson/a5-pll.c
>>>> new file mode 100644
>>>> index 000000000000..d96ed72ef8d4
>>>> --- /dev/null
>>>> +++ b/drivers/clk/meson/a5-pll.c
>>>> @@ -0,0 +1,553 @@
>
> [...]
>
>>>> +static struct clk_regmap gp0_pll = {
>>>> + .data = &(struct clk_regmap_div_data) {
>>>> + .offset = ANACTRL_GP0PLL_CTRL0,
>>>> + .shift = 16,
>>>> + .width = 3,
>>>> + .table = gp0_pll_od_table,
>>>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "gp0_pll",
>>>> + .ops = &clk_regmap_divider_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &gp0_pll_dco.hw
>>>> + },
>>>> + .num_parents = 1,
>>>> + .flags = CLK_SET_RATE_PARENT,
>>>> + },
>>>> +};
>>>> +
>>>> +static const struct reg_sequence hifi_init_regs[] = {
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0X08000000 },
>>> What is bit you are flipping in CTRL0 ? it is suspicious
>>>
>>
>> Yes, CTRL0 and CTRL1 are not necessary here and will be removed in the
>> next version.
>
> That does not really answer my question, does it ?
>
Here it is confirmed with the chip design engineer that the bit27 of
CTRL0 is actually useless, and it is meaningless to write 0 or 1.
>>
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00000000 },
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a295c00 },
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a },
>>>> + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x54540000 }
>>>> +};
>>>> +
>>>> +static const struct pll_mult_range hifi_pll_mult_range = {
>>>> + .min = 125,
>>>> + .max = 250,
>>>> +};
>>>> +
>>>> +static struct clk_regmap hifi_pll_dco = {
>>>> + .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,
>>>> + },
>>>> + .frac = {
>>>> + .reg_off = ANACTRL_HIFIPLL_CTRL1,
>>>> + .shift = 0,
>>>> + .width = 17,
>>>> + },
>>>> + .n = {
>>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> + .shift = 10,
>>>> + .width = 5,
>>>> + },
>>>> + .l = {
>>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> + .shift = 31,
>>>> + .width = 1,
>>>> + },
>>>> + .rst = {
>>>> + .reg_off = ANACTRL_HIFIPLL_CTRL0,
>>>> + .shift = 29,
>>>> + .width = 1,
>>>> + },
>>>> + .range = &hifi_pll_mult_range,
>>>> + .init_regs = hifi_init_regs,
>>>> + .init_count = ARRAY_SIZE(hifi_init_regs),
>>>> + .frac_max = 100000,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "hifi_pll_dco",
>>>> + .ops = &meson_clk_pll_ops,
>>>> + .parent_data = &(const struct clk_parent_data) {
>>>> + .fw_name = "xtal_24m",
>>>> + },
>>>> + .num_parents = 1,
>>>> + },
>>>> +};
>>>> +
>>>> +/* The maximum frequency divider supports is 16, not 128(2^7) */
>>>> +static const struct clk_div_table hifi_pll_od_table[] = {
>>>> + { 0, 1 },
>>>> + { 1, 2 },
>>>> + { 2, 4 },
>>>> + { 3, 8 },
>>> Why don't you ajust the mask then ? Looks like a POW_OF_2 basic
>>> dividider to me.
>>>
>>
>> The maximum frequency division value above the design document is 8,
>> such as the configuration 4/5/6... The actual frequency division value
>> is still 8, so this table is defined, why there is this restriction in
>> detail I am not clear about.
>>
>> Will add these comment ot describe it.
>
> I'm not asking you to add a comment.
> With your explanation, my comment still stands.
>
>>
>>>> + { /* sentinel */ }
>>>> +};
>>>> +
>>>> +static struct clk_regmap hifi_pll = {
>>>> + .data = &(struct clk_regmap_div_data) {
>>>> + .offset = ANACTRL_HIFIPLL_CTRL0,
>>>> + .shift = 16,
>>>> + .width = 3,
>>>> + .table = hifi_pll_od_table,
>>>> + .flags = CLK_DIVIDER_POWER_OF_TWO,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "hifi_pll",
>>>> + .ops = &clk_regmap_divider_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &hifi_pll_dco.hw
>>>> + },
>>>> + .num_parents = 1,
>>>> + .flags = CLK_SET_RATE_PARENT,
>>>> + },
>>>> +};
>>>> +
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver
2024-09-30 10:16 ` Jerome Brunet
@ 2024-10-12 5:50 ` Xianwei Zhao
0 siblings, 0 replies; 17+ messages in thread
From: Xianwei Zhao @ 2024-10-12 5:50 UTC (permalink / raw)
To: Jerome Brunet
Cc: Xianwei Zhao via B4 Relay, Neil Armstrong, Michael Turquette,
Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chuan Liu, Kevin Hilman, Martin Blumenstingl, linux-amlogic,
linux-clk, devicetree, linux-kernel, linux-arm-kernel
Hi Jerome,
Thanks for your reply.
On 2024/9/30 18:16, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
> On Sun 29 Sep 2024 at 16:44, Xianwei Zhao <xianwei.zhao@amlogic.com> wrote:
>
> [...]
>
>>>> +static A4_SYS_GATE(sys_eth_mac, CLKCTRL_SYS_CLK_EN0_REG0, 26, 0);
>>>> +
>>>> +/*
>>>> + * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller).
>>>> + * After clock is disabled, The GIC cannot work properly. At present, the driver
>>>> + * used by our GIC is the public driver in kernel, and there is no management
>>>> + * clock in the driver.
>>>> + */
>>>> +static A4_SYS_GATE(sys_gic, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL);
>>> The GIC has a driver. If it needs clock, maybe it should request it and
>>> enable it, maybe as optional.
>>>
>>
>> This has been explained in C3. GIC is a public driver that does not
>> reference clock, so you suggest setting it as CRITICAL and adding the
>> "FIXME" annotation.
>
> Yes indeed ... and at some point, it is expected something will be done
> a actually fix the situation ... not just pile-up FIXME comments.
>
> Adding a clock to a driver that should have one seems doable.
>
>>
>>>> +static A4_SYS_GATE(sys_rama, CLKCTRL_SYS_CLK_EN0_REG0, 28, 0);
>>>> +
>>>> +/*
>>>> + * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network
>>>> + * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC,
>>>> + * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the
>>>> + * system. After clock is disabled, The NIC cannot work.
>>>> + */
>>> This comment looks like a clock that should be passed as ressource to a
>>> bus or power-domain to be properly manage. This is a pattern that keeps
>>> on repeating. I will not block you on it this time around but I strong
>>> suggest you fix up the situation on the related platform. Next time
>>> around, the reason won't be a valid one.
>>>
>>
>> There are too many modules associated with this clock... The most important
>> is the inclusion of some system-level modules that are not managed by the
>> driver in the kernel and cannot close their clocks, perhaps it is not
>> appropriate to describe it here.
>>
>> In the next version I moved it to scmi-clk for management?
>
> No. The number of module associated with a clock should not be a
> concern and SCMI should not be a 'Hide all the things I don't want to do
> in linux things'.
>
> You've got a bus that needs a clocks. There are possibilities associate
> a clock with bus in DT, either directly or through power-domains. Please
> do it correctly.
>
I also wanted to process these key clocks in scmi-clk for the following
reasons:
1 These clocks seriously affect system security and stability, and are
managed in the security environment (BL31). Under bl31 we will add
additional judgment logic to these clocks: If the kernel is in the
runtime stage, critical sys_clk/axi_clk such as GIC/NIC/CPU_DMC are not
allowed to disable (these clocks can be closed during deep sleep,
because the aocpu is always alive to receive and process interrupts
normally), this can also prevent attacks.
2 Register permissions corresponding to sys_clk/axi_clk can be
configured in the TEE environment. After configuration, the clock cannot
be disabled by writing registers in the REE environment.
3 This driver is used to manage clocks related to general peripherals.
Clocks that affect system security are handled in the security
environment through scmi-clk.
>>
>>>> +static A4_SYS_GATE(sys_big_nic, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL);
>>>> +static A4_SYS_GATE(sys_ramb, CLKCTRL_SYS_CLK_EN0_REG0, 30, 0);
>>>> +static A4_SYS_GATE(sys_audio_top, CLKCTRL_SYS_CLK_EN0_REG1, 0, 0);
>>>> +static A4_SYS_GATE(sys_audio_vad, CLKCTRL_SYS_CLK_EN0_REG1, 1, 0);
>>>> +static A4_SYS_GATE(sys_usb, CLKCTRL_SYS_CLK_EN0_REG1, 2, 0);
>>>> +static A4_SYS_GATE(sys_sd_emmc_a, CLKCTRL_SYS_CLK_EN0_REG1, 3, 0);
>>>> +static A4_SYS_GATE(sys_sd_emmc_c, CLKCTRL_SYS_CLK_EN0_REG1, 4, 0);
>>>> +static A4_SYS_GATE(sys_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG1, 5, 0);
>>>> +static A4_SYS_GATE(sys_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG1, 6, 0);
>>>> +static A4_SYS_GATE(sys_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG1, 7, 0);
>>>> +static A4_SYS_GATE(sys_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG1, 8, 0);
>>>> +static A4_SYS_GATE(sys_spicc_1, CLKCTRL_SYS_CLK_EN0_REG1, 9, 0);
>>>> +static A4_SYS_GATE(sys_spicc_0, CLKCTRL_SYS_CLK_EN0_REG1, 10, 0);
>>>> +static A4_SYS_GATE(sys_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 11, 0);
>>>> +static A4_SYS_GATE(sys_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 12, 0);
>>>> +static A4_SYS_GATE(sys_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 13, 0);
>>>> +static A4_SYS_GATE(sys_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 14, 0);
>>>> +static A4_SYS_GATE(sys_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 15, 0);
>>>> +static A4_SYS_GATE(sys_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 16, 0);
>>>> +static A4_SYS_GATE(sys_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 17, 0);
>>>> +static A4_SYS_GATE(sys_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG1, 18, 0);
>>>> +static A4_SYS_GATE(sys_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG1, 19, 0);
>>>> +static A4_SYS_GATE(sys_rtc, CLKCTRL_SYS_CLK_EN0_REG1, 21, 0);
>>>> +
>>>> +#define A4_AXI_GATE(_name, _reg, _bit, _flags) \
>>>> + A4_CLK_GATE(_name, _reg, _bit, axiclk, \
>>>> + &clk_regmap_gate_ops, _flags)
>>>> +
>>>> +static A4_AXI_GATE(axi_audio_vad, CLKCTRL_AXI_CLK_EN0, 0, 0);
>>>> +static A4_AXI_GATE(axi_audio_top, CLKCTRL_AXI_CLK_EN0, 1, 0);
>>>> +
>>>> +/*
>>>> + * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After
>>>> + * clock is disabled, The NIC cannot work.
>>>> + */
>>>> +static A4_AXI_GATE(axi_sys_nic, CLKCTRL_AXI_CLK_EN0, 2, CLK_IS_CRITICAL);
>>>> +static A4_AXI_GATE(axi_ramb, CLKCTRL_AXI_CLK_EN0, 5, 0);
>>>> +static A4_AXI_GATE(axi_rama, CLKCTRL_AXI_CLK_EN0, 6, 0);
>>>> +
>>>> +/*
>>>> + * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses
>>>> + * the DDR. After clock is disabled, The CPU will not have access to the DDR.
>>>> + */
>>>> +static A4_AXI_GATE(axi_cpu_dmc, CLKCTRL_AXI_CLK_EN0, 7, CLK_IS_CRITICAL);
>>>> +static A4_AXI_GATE(axi_nna, CLKCTRL_AXI_CLK_EN0, 12, 0);
>>>> +
>>>> +/*
>>>> + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO,
>>>> + * sec_top, USB, Audio) to access the AXI bus of the DDR.
>>>> + */
>>> Same.
>>>
>>
>> These normal peripheral drivers manage the clock without a problem.
>>
>>>> +static A4_AXI_GATE(axi_dev1_dmc, CLKCTRL_AXI_CLK_EN0, 13, 0);
>>>> +
>>>> +/*
>>>> + * NOTE: axi_dev0_dmc provides the clock for the peripherals(ETH and SPICC)
>>>> + * to access the AXI bus of the DDR.
>>>> + */
>>>> +static A4_AXI_GATE(axi_dev0_dmc, CLKCTRL_AXI_CLK_EN0, 14, 0);
>>>> +static A4_AXI_GATE(axi_dsp_dmc, CLKCTRL_AXI_CLK_EN0, 15, 0);
>>>> +
>>>> +static struct clk_regmap clk_12_24m_in = {
>>>> + .data = &(struct clk_regmap_gate_data) {
>>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>>> + .bit_idx = 11,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "clk_12_24m_in",
>>>> + .ops = &clk_regmap_gate_ops,
>>>> + .parent_data = &(const struct clk_parent_data) {
>>>> + .fw_name = "xtal_24m",
>>>> + },
>>>> + .num_parents = 1,
>>>> + },
>>>> +};
>>>> +
>>>> +static struct clk_regmap clk_12_24m = {
>>>> + .data = &(struct clk_regmap_div_data) {
>>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>>> + .shift = 10,
>>>> + .width = 1,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "clk_12_24m",
>>>> + .ops = &clk_regmap_divider_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &clk_12_24m_in.hw
>>>> + },
>>>> + .num_parents = 1,
>>>> + },
>>>> +};
>>>> +
>>>> +/* FIXME: set value 0 will div by 2 like value 1 */
>>> Again, it is fine when it happens once, like the c3.
>>> When the pattern starts repeating, it is time to do something about it.
>>>
>>
>> The corresponding suggestions have been made to the hardware designer, but
>> now the designed chip cannot be repaired.
>
> Not asking to fix the HW (although that would be nice if you could)
> The HW is what it is. The SW needs fixing. That you can do.
>
>>
>>>> +static struct clk_regmap fclk_25m_div = {
>>>> + .data = &(struct clk_regmap_div_data) {
>>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>>> + .shift = 0,
>>>> + .width = 8,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "fclk_25m_div",
>>>> + .ops = &clk_regmap_divider_ops,
>>>> + .parent_data = &(const struct clk_parent_data) {
>>>> + .fw_name = "fix",
>>>> + },
>>>> + .num_parents = 1,
>>>> + },
>>>> +};
>>>> +
>>>> +static struct clk_regmap fclk_25m = {
>>>> + .data = &(struct clk_regmap_gate_data) {
>>>> + .offset = CLKCTRL_CLK12_24_CTRL,
>>>> + .bit_idx = 12,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "fclk_25m",
>>>> + .ops = &clk_regmap_gate_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &fclk_25m_div.hw
>>>> + },
>>>> + .num_parents = 1,
>>>> + .flags = CLK_SET_RATE_PARENT,
>>>> + },
>>>> +};
>>>> +
>>>> +/*
>>>> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk)
>>>> + * is manged by clock measures module. Their hardware are out of clock tree.
>>> Yet, they exist and should be part of the bindings since they are
>>> obviously input to this clock.
>>>
>>
>> Will add it to bindings, as optional input clock source.
>>
>>>> + * Channel 4 5 8 9 10 11 13 14 15 16 18 are not connected.
>>>> + *
>>>> + * gp1 is designed for DSU (DynamIQ Shared Unit) alone. It cannot be changed
>>>> + * arbitrarily. gp1 is read-only in the kernel and is only open for debug purposes.
>>>> + */
>>>> +static u32 gen_parent_table[] = { 0, 1, 2, 6, 7, 17, 19, 20, 21, 22, 23, 24, 25,
>>>> + 26, 27, 28};
>>>> +
>>>> +static const struct clk_parent_data gen_parent_data[] = {
>>>> + { .fw_name = "oscin" },
>>>> + { .hw = &rtc_clk.hw },
>>>> + { .fw_name = "sysplldiv16" },
>>>> + { .fw_name = "gp1" },
>>>> + { .fw_name = "hifi" },
>>>> + { .fw_name = "cpudiv16" },
>>>> + { .fw_name = "fdiv2" },
>>>> + { .fw_name = "fdiv2p5" },
>>>> + { .fw_name = "fdiv3" },
>>>> + { .fw_name = "fdiv4" },
>>>> + { .fw_name = "fdiv5" },
>>>> + { .fw_name = "fdiv7" },
>>>> + { .fw_name = "mpll0" },
>>>> + { .fw_name = "mpll1" },
>>>> + { .fw_name = "mpll2" },
>>>> + { .fw_name = "mpll3" }
>>>> +};
>
> [...]
>
>>>> +
>>>> +static struct clk_regmap pwm_h_sel =
>>>> + AML_PWM_CLK_MUX(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25);
>>>> +static struct clk_regmap pwm_h_div =
>>>> + AML_PWM_CLK_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16);
>>>> +static struct clk_regmap pwm_h =
>>>> + AML_PWM_CLK_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24);
>>>> +
>>>> +/* Channel 7 is gp1. */
>>> and ? if GP1 is RO, why can't you add it here ?
>>>
>>
>> gp1_pll is a special clock for DSU, it is integrated into dsu_clk, we
>> don't want other modules to reference it.
>>
>> My understanding is that gp1_pll should not be provided to the peripheral
>> clock tree, perhaps this is a redundant design.
>
> Then /* Channel 7 is gp1 which is reserved for DSU */
>
> Note that if GP1 is actually RO and DSU does not change the rate at
> runtime through other means, then listing GP1 here should not be a
> problem, spi would just be user of an available PLL.
>
cpufreq(DVFS) driver will still dynamically adjust the frequency of gp1
after running, but I configured gp1 as RO under bl31, and it is risky to
open it to other peripheral modules.
For example, when the frequency of spicc is set, the frequency of gp1 is
just enough to meet the requirements of spicc. At this time, spicc will
switch to gp1. Later, when the cpufreq driver dynamically sets the
frequency of gp1, it will be a disaster for spicc.... This may also
happen in the future with peripherals that support hifi_pll (audio
adaptation sampling rate and synchronization with video may dynamically
adjust the hifipll frequency).
>>
>>>> +static const struct clk_parent_data spicc_parent_data[] = {
>>>> + { .fw_name = "oscin" },
>>>> + { .fw_name = "sysclk" },
>>>> + { .fw_name = "fdiv4" },
>>>> + { .fw_name = "fdiv3" },
>>>> + { .fw_name = "fdiv2" },
>>>> + { .fw_name = "fdiv5" },
>>>> + { .fw_name = "fdiv7" }
>>>> +};
>>>> +
>>>> +static struct clk_regmap spicc_0_sel = {
>>>> + .data = &(struct clk_regmap_mux_data) {
>>>> + .offset = CLKCTRL_SPICC_CLK_CTRL,
>>>> + .mask = 0x7,
>>>> + .shift = 7,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "spicc_0_sel",
>>>> + .ops = &clk_regmap_mux_ops,
>>>> + .parent_data = spicc_parent_data,
>>>> + .num_parents = ARRAY_SIZE(spicc_parent_data),
>>>> + },
>>>> +};
>
> [...]
>
>>>> +
>>>> +static struct clk_regmap dspa_1 = {
>>>> + .data = &(struct clk_regmap_gate_data) {
>>>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>>>> + .bit_idx = 29,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "dspa_1",
>>>> + .ops = &clk_regmap_gate_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &dspa_1_div.hw
>>>> + },
>>>> + .num_parents = 1,
>>>> + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
>>> A word about SET_RATE_GATE ?
>>>
>>
>> Look at the response to one of the questions below.
>
> Still a word ? your comment below does justify this flag clearly.
>
CLK_SET_RATE_GATE is to enable glitch free mux to perform ping-pong
switching.
>>
>>>> + },
>>>> +};
>>>> +
>>>> +static struct clk_regmap dspa = {
>>>> + .data = &(struct clk_regmap_mux_data){
>>>> + .offset = CLKCTRL_DSPA_CLK_CTRL0,
>>>> + .mask = 0x1,
>>>> + .shift = 15,
>>>> + },
>>>> + .hw.init = &(struct clk_init_data) {
>>>> + .name = "dspa",
>>>> + .ops = &clk_regmap_mux_ops,
>>>> + .parent_hws = (const struct clk_hw *[]) {
>>>> + &dspa_0.hw,
>>>> + &dspa_1.hw
>>>> + },
>>>> + .num_parents = 2,
>>>> + /*
>>>> + * NOTE: This level of mux is "no glitch mux", and mux_0
>>>> + * (here dspa_0) is not only the clock source for mux, but also
>>>> + * provides a working clock for "no glitch mux". "no glitch mux"
>>>> + * can be switched only when mux_0 has a clock input. Therefore,
>>>> + * add flag CLK_OPS_PARENT_ENABLE to ensure that mux_0 has clock
>>>> + * when "no glitch mux" works.
>>>> + */
>>>> + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
>>> Humm CLK_OPS_PARENT_ENABLE is not how we have handling glitch free mux
>>> so far. What changed ?
>>>
>>
>> This is a hidden problem we have discovered in recent years, the previous
>> chip use is ping-pong switching "no-glitch-mux/glitch free" have this
>> problem. If mux_0 does not have a clock "no-glitch-mux", it will not be
>> able to switch channels, and I will organize and submit patch to fix it
>> later.
>
> The NOTE comment and what the code does are not aligned.
> * Your comment says that input #0 must be enabled for the mux to work
> * The flag ensure that parent is enabled before switching to it. There
> is nothing specific about input #0
>
This has been explained in another patch. Configuring
CLK_OPS_PARENT_ENABLE can ensure that both channel 0 and channel 1 are
enabled during mux switching. In fact, we only need to ensure that
channel 0 is enabled.
>>
>>>> + },
>>>> +};
>>>> +
>>>> +/* Channel 6 is gp1. */
>>>> +static u32 nna_parent_table[] = { 0, 1, 2, 3, 4, 5, 7};
>>>> +
>>>> +static const struct clk_parent_data nna_parent_data[] = {
>>>> + { .fw_name = "oscin" },
>>>> + { .fw_name = "fdiv2p5" },
>>>> + { .fw_name = "fdiv4" },
>>>> + { .fw_name = "fdiv3" },
>>>> + { .fw_name = "fdiv5" },
>>>> + { .fw_name = "fdiv2" },
>>>> + { .fw_name = "hifi" }
>>>> +};
>
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2024-10-12 5:50 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-14 5:25 [PATCH 0/5] Add A5 SoC PLLs and Peripheral clock Xianwei Zhao via B4 Relay
2024-09-14 5:25 ` [PATCH 1/5] dt-bindings: clock: add Amlogic A5 PLL clock controller Xianwei Zhao via B4 Relay
2024-09-18 16:06 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 2/5] dt-bindings: clock: add Amlogic A5 SCMI clock controller support Xianwei Zhao via B4 Relay
2024-09-18 16:07 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 3/5] dt-bindings: clock: add Amlogic A5 peripherals clock controller Xianwei Zhao via B4 Relay
2024-09-18 16:13 ` Rob Herring (Arm)
2024-09-14 5:25 ` [PATCH 4/5] clk: meson: add support for the A5 SoC PLL clock Xianwei Zhao via B4 Relay
2024-09-24 14:45 ` Jerome Brunet
2024-09-29 8:17 ` Xianwei Zhao
2024-09-30 9:41 ` Jerome Brunet
2024-10-12 5:43 ` Xianwei Zhao
2024-09-14 5:25 ` [PATCH 5/5] clk: meson: add A5 clock peripherals controller driver Xianwei Zhao via B4 Relay
2024-09-24 15:09 ` Jerome Brunet
2024-09-29 8:44 ` Xianwei Zhao
2024-09-30 10:16 ` Jerome Brunet
2024-10-12 5:50 ` Xianwei Zhao
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).