From 5437753728ac40a0410f3a4c6c471d0ab9919ceb Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 12 Dec 2025 10:26:14 +0800 Subject: [PATCH 01/38] dt-bindings: clock: add Amlogic T7 PLL clock controller Add DT bindings for the PLL clock controller of the Amlogic T7 SoC family. Signed-off-by: Jian Hu Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20251212022619.3072132-2-jian.hu@amlogic.com Signed-off-by: Jerome Brunet --- .../bindings/clock/amlogic,t7-pll-clkc.yaml | 114 ++++++++++++++++++ .../dt-bindings/clock/amlogic,t7-pll-clkc.h | 56 +++++++++ 2 files changed, 170 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml new file mode 100644 index 000000000000..49c61f65deff --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/amlogic,t7-pll-clkc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic T7 PLL Clock Control Controller + +maintainers: + - Neil Armstrong + - Jerome Brunet + - Jian Hu + - Xianwei Zhao + +properties: + compatible: + enum: + - amlogic,t7-gp0-pll + - amlogic,t7-gp1-pll + - amlogic,t7-hifi-pll + - amlogic,t7-pcie-pll + - amlogic,t7-mpll + - amlogic,t7-hdmi-pll + - amlogic,t7-mclk-pll + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + items: + - description: mclk pll input oscillator gate + - description: oscillator input clock source for mclk_sel_0 + - description: fixed input clock source for mclk_sel_0 + minItems: 1 + + clock-names: + items: + - const: in0 + - const: in1 + - const: in2 + minItems: 1 + +required: + - compatible + - '#clock-cells' + - reg + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + const: amlogic,t7-mclk-pll + + then: + properties: + clocks: + minItems: 3 + + clock-names: + minItems: 3 + + - if: + properties: + compatible: + contains: + enum: + - amlogic,t7-gp0-pll + - amlogic,t7-gp1--pll + - amlogic,t7-hifi-pll + - amlogic,t7-pcie-pll + - amlogic,t7-mpll + - amlogic,t7-hdmi-pll + + then: + properties: + clocks: + maxItems: 1 + + clock-names: + maxItems: 1 + +additionalProperties: false + +examples: + - | + apb { + #address-cells = <2>; + #size-cells = <2>; + + clock-controller@8080 { + compatible = "amlogic,t7-gp0-pll"; + reg = <0 0x8080 0 0x20>; + clocks = <&scmi_clk 2>; + clock-names = "in0"; + #clock-cells = <1>; + }; + + clock-controller@8300 { + compatible = "amlogic,t7-mclk-pll"; + reg = <0 0x8300 0 0x18>; + clocks = <&scmi_clk 2>, + <&xtal>, + <&scmi_clk 31>; + clock-names = "in0", "in1", "in2"; + #clock-cells = <1>; + }; + }; diff --git a/include/dt-bindings/clock/amlogic,t7-pll-clkc.h b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h new file mode 100644 index 000000000000..e2481f2f1163 --- /dev/null +++ b/include/dt-bindings/clock/amlogic,t7-pll-clkc.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved + */ + +#ifndef __T7_PLL_CLKC_H +#define __T7_PLL_CLKC_H + +/* GP0 */ +#define CLKID_GP0_PLL_DCO 0 +#define CLKID_GP0_PLL 1 + +/* GP1 */ +#define CLKID_GP1_PLL_DCO 0 +#define CLKID_GP1_PLL 1 + +/* HIFI */ +#define CLKID_HIFI_PLL_DCO 0 +#define CLKID_HIFI_PLL 1 + +/* PCIE */ +#define CLKID_PCIE_PLL_DCO 0 +#define CLKID_PCIE_PLL_DCO_DIV2 1 +#define CLKID_PCIE_PLL_OD 2 +#define CLKID_PCIE_PLL 3 + +/* MPLL */ +#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 + +/* HDMI */ +#define CLKID_HDMI_PLL_DCO 0 +#define CLKID_HDMI_PLL_OD 1 +#define CLKID_HDMI_PLL 2 + +/* MCLK */ +#define CLKID_MCLK_PLL_DCO 0 +#define CLKID_MCLK_PRE 1 +#define CLKID_MCLK_PLL 2 +#define CLKID_MCLK_0_SEL 3 +#define CLKID_MCLK_0_DIV2 4 +#define CLKID_MCLK_0_PRE 5 +#define CLKID_MCLK_0 6 +#define CLKID_MCLK_1_SEL 7 +#define CLKID_MCLK_1_DIV2 8 +#define CLKID_MCLK_1_PRE 9 +#define CLKID_MCLK_1 10 + +#endif /* __T7_PLL_CLKC_H */ From f5d473e96fe0ae46a2da79c96b3623b3be37b5a0 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 12 Dec 2025 10:26:15 +0800 Subject: [PATCH 02/38] dt-bindings: clock: add Amlogic T7 SCMI clock controller Add DT bindings for the SCMI clock controller of the Amlogic T7 SoC family. Signed-off-by: Jian Hu Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251212022619.3072132-3-jian.hu@amlogic.com Signed-off-by: Jerome Brunet --- include/dt-bindings/clock/amlogic,t7-scmi.h | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 include/dt-bindings/clock/amlogic,t7-scmi.h diff --git a/include/dt-bindings/clock/amlogic,t7-scmi.h b/include/dt-bindings/clock/amlogic,t7-scmi.h new file mode 100644 index 000000000000..27bd257bd4ea --- /dev/null +++ b/include/dt-bindings/clock/amlogic,t7-scmi.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved + */ + +#ifndef __T7_SCMI_CLKC_H +#define __T7_SCMI_CLKC_H + +#define CLKID_DDR_PLL_OSC 0 +#define CLKID_AUD_PLL_OSC 1 +#define CLKID_TOP_PLL_OSC 2 +#define CLKID_TCON_PLL_OSC 3 +#define CLKID_USB_PLL0_OSC 4 +#define CLKID_USB_PLL1_OSC 5 +#define CLKID_MCLK_PLL_OSC 6 +#define CLKID_PCIE_OSC 7 +#define CLKID_ETH_PLL_OSC 8 +#define CLKID_PCIE_REFCLK_PLL_OSC 9 +#define CLKID_EARC_OSC 10 +#define CLKID_SYS1_PLL_OSC 11 +#define CLKID_HDMI_PLL_OSC 12 +#define CLKID_SYS_CLK 13 +#define CLKID_AXI_CLK 14 +#define CLKID_FIXED_PLL_DCO 15 +#define CLKID_FIXED_PLL 16 +#define CLKID_FCLK_DIV2_DIV 17 +#define CLKID_FCLK_DIV2 18 +#define CLKID_FCLK_DIV2P5_DIV 19 +#define CLKID_FCLK_DIV2P5 20 +#define CLKID_FCLK_DIV3_DIV 21 +#define CLKID_FCLK_DIV3 22 +#define CLKID_FCLK_DIV4_DIV 23 +#define CLKID_FCLK_DIV4 24 +#define CLKID_FCLK_DIV5_DIV 25 +#define CLKID_FCLK_DIV5 26 +#define CLKID_FCLK_DIV7_DIV 27 +#define CLKID_FCLK_DIV7 28 +#define CLKID_FCLK_50M_DIV 29 +#define CLKID_FCLK_50M 30 +#define CLKID_CPU_CLK 31 +#define CLKID_A73_CLK 32 +#define CLKID_CPU_CLK_DIV16_DIV 33 +#define CLKID_CPU_CLK_DIV16 34 +#define CLKID_A73_CLK_DIV16_DIV 35 +#define CLKID_A73_CLK_DIV16 36 + +#endif /* __T7_SCMI_CLKC_H */ From b4156204e0f5d66e5943d9836e42d01d6e5e12fb Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 12 Dec 2025 10:26:16 +0800 Subject: [PATCH 03/38] dt-bindings: clock: add Amlogic T7 peripherals clock controller Add DT bindings for the peripheral clock controller of the Amlogic T7 SoC family. Signed-off-by: Jian Hu Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20251212022619.3072132-4-jian.hu@amlogic.com Signed-off-by: Jerome Brunet --- .../clock/amlogic,t7-peripherals-clkc.yaml | 116 +++++++++ .../clock/amlogic,t7-peripherals-clkc.h | 228 ++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml new file mode 100644 index 000000000000..55bb73707d58 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/amlogic,t7-peripherals-clkc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic T7 Peripherals Clock Controller + +maintainers: + - Neil Armstrong + - Jerome Brunet + - Xianwei Zhao + - Jian Hu + +properties: + compatible: + const: amlogic,t7-peripherals-clkc + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + minItems: 14 + items: + - description: input oscillator + - description: input sys clk + - description: input fixed 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 hifi pll + - description: input gp0 pll + - description: input gp1 pll + - description: input mpll1 + - description: input mpll2 + - description: external input rmii oscillator (optional) + - description: input video pll0 (optional) + - description: external pad input for rtc (optional) + + clock-names: + minItems: 14 + items: + - const: xtal + - const: sys + - const: fix + - const: fdiv2 + - const: fdiv2p5 + - const: fdiv3 + - const: fdiv4 + - const: fdiv5 + - const: fdiv7 + - const: hifi + - const: gp0 + - const: gp1 + - const: mpll1 + - const: mpll2 + - const: ext_rmii + - const: vid_pll0 + - const: ext_rtc + +required: + - compatible + - '#clock-cells' + - reg + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + apb { + #address-cells = <2>; + #size-cells = <2>; + + clkc_periphs:clock-controller@0 { + compatible = "amlogic,t7-peripherals-clkc"; + reg = <0 0x0 0 0x1c8>; + #clock-cells = <1>; + clocks = <&xtal>, + <&scmi_clk 13>, + <&scmi_clk 16>, + <&scmi_clk 18>, + <&scmi_clk 20>, + <&scmi_clk 22>, + <&scmi_clk 24>, + <&scmi_clk 26>, + <&scmi_clk 28>, + <&hifi 1>, + <&gp0 1>, + <&gp1 1>, + <&mpll 4>, + <&mpll 6>; + clock-names = "xtal", + "sys", + "fix", + "fdiv2", + "fdiv2p5", + "fdiv3", + "fdiv4", + "fdiv5", + "fdiv7", + "hifi", + "gp0", + "gp1", + "mpll1", + "mpll2"; + }; + }; diff --git a/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h new file mode 100644 index 000000000000..32c4b62037de --- /dev/null +++ b/include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved + */ + +#ifndef __T7_PERIPHERALS_CLKC_H +#define __T7_PERIPHERALS_CLKC_H + +#define CLKID_RTC_DUALDIV_IN 0 +#define CLKID_RTC_DUALDIV_DIV 1 +#define CLKID_RTC_DUALDIV_SEL 2 +#define CLKID_RTC_DUALDIV 3 +#define CLKID_RTC 4 +#define CLKID_CECA_DUALDIV_IN 5 +#define CLKID_CECA_DUALDIV_DIV 6 +#define CLKID_CECA_DUALDIV_SEL 7 +#define CLKID_CECA_DUALDIV 8 +#define CLKID_CECA 9 +#define CLKID_CECB_DUALDIV_IN 10 +#define CLKID_CECB_DUALDIV_DIV 11 +#define CLKID_CECB_DUALDIV_SEL 12 +#define CLKID_CECB_DUALDIV 13 +#define CLKID_CECB 14 +#define CLKID_SC_SEL 15 +#define CLKID_SC_DIV 16 +#define CLKID_SC 17 +#define CLKID_DSPA_0_SEL 18 +#define CLKID_DSPA_0_DIV 19 +#define CLKID_DSPA_0 20 +#define CLKID_DSPA_1_SEL 21 +#define CLKID_DSPA_1_DIV 22 +#define CLKID_DSPA_1 23 +#define CLKID_DSPA 24 +#define CLKID_DSPB_0_SEL 25 +#define CLKID_DSPB_0_DIV 26 +#define CLKID_DSPB_0 27 +#define CLKID_DSPB_1_SEL 28 +#define CLKID_DSPB_1_DIV 29 +#define CLKID_DSPB_1 30 +#define CLKID_DSPB 31 +#define CLKID_24M 32 +#define CLKID_24M_DIV2 33 +#define CLKID_12M 34 +#define CLKID_25M_DIV 35 +#define CLKID_25M 36 +#define CLKID_ANAKIN_0_SEL 37 +#define CLKID_ANAKIN_0_DIV 38 +#define CLKID_ANAKIN_0 39 +#define CLKID_ANAKIN_1_SEL 40 +#define CLKID_ANAKIN_1_DIV 41 +#define CLKID_ANAKIN_1 42 +#define CLKID_ANAKIN_01_SEL 43 +#define CLKID_ANAKIN 44 +#define CLKID_TS_DIV 45 +#define CLKID_TS 46 +#define CLKID_MIPI_CSI_PHY_0_SEL 47 +#define CLKID_MIPI_CSI_PHY_0_DIV 48 +#define CLKID_MIPI_CSI_PHY_0 49 +#define CLKID_MIPI_CSI_PHY_1_SEL 50 +#define CLKID_MIPI_CSI_PHY_1_DIV 51 +#define CLKID_MIPI_CSI_PHY_1 52 +#define CLKID_MIPI_CSI_PHY 53 +#define CLKID_MIPI_ISP_SEL 54 +#define CLKID_MIPI_ISP_DIV 55 +#define CLKID_MIPI_ISP 56 +#define CLKID_MALI_0_SEL 57 +#define CLKID_MALI_0_DIV 58 +#define CLKID_MALI_0 59 +#define CLKID_MALI_1_SEL 60 +#define CLKID_MALI_1_DIV 61 +#define CLKID_MALI_1 62 +#define CLKID_MALI 63 +#define CLKID_ETH_RMII_SEL 64 +#define CLKID_ETH_RMII_DIV 65 +#define CLKID_ETH_RMII 66 +#define CLKID_FCLK_DIV2_DIV8 67 +#define CLKID_ETH_125M 68 +#define CLKID_SD_EMMC_A_SEL 69 +#define CLKID_SD_EMMC_A_DIV 70 +#define CLKID_SD_EMMC_A 71 +#define CLKID_SD_EMMC_B_SEL 72 +#define CLKID_SD_EMMC_B_DIV 73 +#define CLKID_SD_EMMC_B 74 +#define CLKID_SD_EMMC_C_SEL 75 +#define CLKID_SD_EMMC_C_DIV 76 +#define CLKID_SD_EMMC_C 77 +#define CLKID_SPICC0_SEL 78 +#define CLKID_SPICC0_DIV 79 +#define CLKID_SPICC0 80 +#define CLKID_SPICC1_SEL 81 +#define CLKID_SPICC1_DIV 82 +#define CLKID_SPICC1 83 +#define CLKID_SPICC2_SEL 84 +#define CLKID_SPICC2_DIV 85 +#define CLKID_SPICC2 86 +#define CLKID_SPICC3_SEL 87 +#define CLKID_SPICC3_DIV 88 +#define CLKID_SPICC3 89 +#define CLKID_SPICC4_SEL 90 +#define CLKID_SPICC4_DIV 91 +#define CLKID_SPICC4 92 +#define CLKID_SPICC5_SEL 93 +#define CLKID_SPICC5_DIV 94 +#define CLKID_SPICC5 95 +#define CLKID_SARADC_SEL 96 +#define CLKID_SARADC_DIV 97 +#define CLKID_SARADC 98 +#define CLKID_PWM_A_SEL 99 +#define CLKID_PWM_A_DIV 100 +#define CLKID_PWM_A 101 +#define CLKID_PWM_B_SEL 102 +#define CLKID_PWM_B_DIV 103 +#define CLKID_PWM_B 104 +#define CLKID_PWM_C_SEL 105 +#define CLKID_PWM_C_DIV 106 +#define CLKID_PWM_C 107 +#define CLKID_PWM_D_SEL 108 +#define CLKID_PWM_D_DIV 109 +#define CLKID_PWM_D 110 +#define CLKID_PWM_E_SEL 111 +#define CLKID_PWM_E_DIV 112 +#define CLKID_PWM_E 113 +#define CLKID_PWM_F_SEL 114 +#define CLKID_PWM_F_DIV 115 +#define CLKID_PWM_F 116 +#define CLKID_PWM_AO_A_SEL 117 +#define CLKID_PWM_AO_A_DIV 118 +#define CLKID_PWM_AO_A 119 +#define CLKID_PWM_AO_B_SEL 120 +#define CLKID_PWM_AO_B_DIV 121 +#define CLKID_PWM_AO_B 122 +#define CLKID_PWM_AO_C_SEL 123 +#define CLKID_PWM_AO_C_DIV 124 +#define CLKID_PWM_AO_C 125 +#define CLKID_PWM_AO_D_SEL 126 +#define CLKID_PWM_AO_D_DIV 127 +#define CLKID_PWM_AO_D 128 +#define CLKID_PWM_AO_E_SEL 129 +#define CLKID_PWM_AO_E_DIV 130 +#define CLKID_PWM_AO_E 131 +#define CLKID_PWM_AO_F_SEL 132 +#define CLKID_PWM_AO_F_DIV 133 +#define CLKID_PWM_AO_F 134 +#define CLKID_PWM_AO_G_SEL 135 +#define CLKID_PWM_AO_G_DIV 136 +#define CLKID_PWM_AO_G 137 +#define CLKID_PWM_AO_H_SEL 138 +#define CLKID_PWM_AO_H_DIV 139 +#define CLKID_PWM_AO_H 140 +#define CLKID_SYS_DDR 141 +#define CLKID_SYS_DOS 142 +#define CLKID_SYS_MIPI_DSI_A 143 +#define CLKID_SYS_MIPI_DSI_B 144 +#define CLKID_SYS_ETHPHY 145 +#define CLKID_SYS_MALI 146 +#define CLKID_SYS_AOCPU 147 +#define CLKID_SYS_AUCPU 148 +#define CLKID_SYS_CEC 149 +#define CLKID_SYS_GDC 150 +#define CLKID_SYS_DESWARP 151 +#define CLKID_SYS_AMPIPE_NAND 152 +#define CLKID_SYS_AMPIPE_ETH 153 +#define CLKID_SYS_AM2AXI0 154 +#define CLKID_SYS_AM2AXI1 155 +#define CLKID_SYS_AM2AXI2 156 +#define CLKID_SYS_SD_EMMC_A 157 +#define CLKID_SYS_SD_EMMC_B 158 +#define CLKID_SYS_SD_EMMC_C 159 +#define CLKID_SYS_SMARTCARD 160 +#define CLKID_SYS_ACODEC 161 +#define CLKID_SYS_SPIFC 162 +#define CLKID_SYS_MSR_CLK 163 +#define CLKID_SYS_IR_CTRL 164 +#define CLKID_SYS_AUDIO 165 +#define CLKID_SYS_ETH 166 +#define CLKID_SYS_UART_A 167 +#define CLKID_SYS_UART_B 168 +#define CLKID_SYS_UART_C 169 +#define CLKID_SYS_UART_D 170 +#define CLKID_SYS_UART_E 171 +#define CLKID_SYS_UART_F 172 +#define CLKID_SYS_AIFIFO 173 +#define CLKID_SYS_SPICC2 174 +#define CLKID_SYS_SPICC3 175 +#define CLKID_SYS_SPICC4 176 +#define CLKID_SYS_TS_A73 177 +#define CLKID_SYS_TS_A53 178 +#define CLKID_SYS_SPICC5 179 +#define CLKID_SYS_G2D 180 +#define CLKID_SYS_SPICC0 181 +#define CLKID_SYS_SPICC1 182 +#define CLKID_SYS_PCIE 183 +#define CLKID_SYS_USB 184 +#define CLKID_SYS_PCIE_PHY 185 +#define CLKID_SYS_I2C_AO_A 186 +#define CLKID_SYS_I2C_AO_B 187 +#define CLKID_SYS_I2C_M_A 188 +#define CLKID_SYS_I2C_M_B 189 +#define CLKID_SYS_I2C_M_C 190 +#define CLKID_SYS_I2C_M_D 191 +#define CLKID_SYS_I2C_M_E 192 +#define CLKID_SYS_I2C_M_F 193 +#define CLKID_SYS_HDMITX_APB 194 +#define CLKID_SYS_I2C_S_A 195 +#define CLKID_SYS_HDMIRX_PCLK 196 +#define CLKID_SYS_MMC_APB 197 +#define CLKID_SYS_MIPI_ISP_PCLK 198 +#define CLKID_SYS_RSA 199 +#define CLKID_SYS_PCLK_SYS_APB 200 +#define CLKID_SYS_A73PCLK_APB 201 +#define CLKID_SYS_DSPA 202 +#define CLKID_SYS_DSPB 203 +#define CLKID_SYS_VPU_INTR 204 +#define CLKID_SYS_SAR_ADC 205 +#define CLKID_SYS_GIC 206 +#define CLKID_SYS_TS_GPU 207 +#define CLKID_SYS_TS_NNA 208 +#define CLKID_SYS_TS_VPU 209 +#define CLKID_SYS_TS_HEVC 210 +#define CLKID_SYS_PWM_AB 211 +#define CLKID_SYS_PWM_CD 212 +#define CLKID_SYS_PWM_EF 213 +#define CLKID_SYS_PWM_AO_AB 214 +#define CLKID_SYS_PWM_AO_CD 215 +#define CLKID_SYS_PWM_AO_EF 216 +#define CLKID_SYS_PWM_AO_GH 217 + +#endif /* __T7_PERIPHERALS_CLKC_H */ From 140f074c312702a1837136e024f5df1309e37251 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 12 Dec 2025 10:26:17 +0800 Subject: [PATCH 04/38] clk: meson: t7: add support for the T7 SoC PLL clock Add PLL clock controller driver for the Amlogic T7 SoC family. Signed-off-by: Jian Hu Link: https://lore.kernel.org/r/20251212022619.3072132-5-jian.hu@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 15 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/t7-pll.c | 1074 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1090 insertions(+) create mode 100644 drivers/clk/meson/t7-pll.c diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 71481607a6d5..e6a059bcf636 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -201,4 +201,19 @@ config COMMON_CLK_S4_PERIPHERALS help Support for the peripherals clock controller on Amlogic S805X2 and S905Y4 devices, AKA S4. Say Y if you want S4 peripherals clock controller to work. + +config COMMON_CLK_T7_PLL + tristate "Amlogic T7 SoC PLL controller support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + imply COMMON_CLK_SCMI + help + Support for the PLL clock controller on Amlogic A311D2 based + device, AKA T7. PLLs are required by most peripheral to operate. + Say Y if you want T7 PLL clock controller to work. + endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index c6998e752c68..8e3f7f94c639 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o +obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o diff --git a/drivers/clk/meson/t7-pll.c b/drivers/clk/meson/t7-pll.c new file mode 100644 index 000000000000..0a622f45fa36 --- /dev/null +++ b/drivers/clk/meson/t7-pll.c @@ -0,0 +1,1074 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + */ + +#include +#include +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" +#include "meson-clkc-utils.h" +#include + +#define GP0PLL_CTRL0 0x00 +#define GP0PLL_CTRL1 0x04 +#define GP0PLL_CTRL2 0x08 +#define GP0PLL_CTRL3 0x0c +#define GP0PLL_CTRL4 0x10 +#define GP0PLL_CTRL5 0x14 +#define GP0PLL_CTRL6 0x18 +#define GP0PLL_STS 0x1c + +#define GP1PLL_CTRL0 0x00 +#define GP1PLL_CTRL1 0x04 +#define GP1PLL_CTRL2 0x08 +#define GP1PLL_CTRL3 0x0c +#define GP1PLL_STS 0x1c + +#define HIFIPLL_CTRL0 0x00 +#define HIFIPLL_CTRL1 0x04 +#define HIFIPLL_CTRL2 0x08 +#define HIFIPLL_CTRL3 0x0c +#define HIFIPLL_CTRL4 0x10 +#define HIFIPLL_CTRL5 0x14 +#define HIFIPLL_CTRL6 0x18 +#define HIFIPLL_STS 0x1c + +#define PCIEPLL_CTRL0 0x00 +#define PCIEPLL_CTRL1 0x04 +#define PCIEPLL_CTRL2 0x08 +#define PCIEPLL_CTRL3 0x0c +#define PCIEPLL_CTRL4 0x10 +#define PCIEPLL_CTRL5 0x14 +#define PCIEPLL_STS 0x18 + +#define MPLL_CTRL0 0x00 +#define MPLL_CTRL1 0x04 +#define MPLL_CTRL2 0x08 +#define MPLL_CTRL3 0x0c +#define MPLL_CTRL4 0x10 +#define MPLL_CTRL5 0x14 +#define MPLL_CTRL6 0x18 +#define MPLL_CTRL7 0x1c +#define MPLL_CTRL8 0x20 +#define MPLL_STS 0x24 + +#define HDMIPLL_CTRL0 0x00 +#define HDMIPLL_CTRL1 0x04 +#define HDMIPLL_CTRL2 0x08 +#define HDMIPLL_CTRL3 0x0c +#define HDMIPLL_CTRL4 0x10 +#define HDMIPLL_CTRL5 0x14 +#define HDMIPLL_CTRL6 0x18 +#define HDMIPLL_STS 0x1c + +#define MCLK_PLL_CNTL0 0x00 +#define MCLK_PLL_CNTL1 0x04 +#define MCLK_PLL_CNTL2 0x08 +#define MCLK_PLL_CNTL3 0x0c +#define MCLK_PLL_CNTL4 0x10 +#define MCLK_PLL_STS 0x14 + +static const struct pll_mult_range t7_media_pll_mult_range = { + .min = 125, + .max = 250, +}; + +static const struct reg_sequence t7_gp0_init_regs[] = { + { .reg = GP0PLL_CTRL1, .def = 0x00000000 }, + { .reg = GP0PLL_CTRL2, .def = 0x00000000 }, + { .reg = GP0PLL_CTRL3, .def = 0x48681c00 }, + { .reg = GP0PLL_CTRL4, .def = 0x88770290 }, + { .reg = GP0PLL_CTRL5, .def = 0x3927200a }, + { .reg = GP0PLL_CTRL6, .def = 0x56540000 }, +}; + +static struct clk_regmap t7_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = GP0PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = GP0PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = GP0PLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = GP0PLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = GP0PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_gp0_init_regs, + .init_count = ARRAY_SIZE(t7_gp0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = GP0PLL_CTRL0, + .shift = 16, + .width = 3, + .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 *[]) { + &t7_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Compared with GP0 PLL, GP1 PLL is a newly designed PLL with + * a DCO range of 1.6GHz to 3.2GHz. + */ +static const struct pll_mult_range t7_gp1_pll_mult_range = { + .min = 67, + .max = 133, +}; + +static const struct reg_sequence t7_gp1_init_regs[] = { + { .reg = GP1PLL_CTRL1, .def = 0x1420500f }, + { .reg = GP1PLL_CTRL2, .def = 0x00023001 }, + { .reg = GP1PLL_CTRL3, .def = 0x00000000 }, +}; + +static struct clk_regmap t7_gp1_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = GP1PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = GP1PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = GP1PLL_CTRL0, + .shift = 16, + .width = 5, + }, + .l = { + .reg_off = GP1PLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = GP1PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_gp1_pll_mult_range, + .init_regs = t7_gp1_init_regs, + .init_count = ARRAY_SIZE(t7_gp1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_gp1_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = GP1PLL_CTRL0, + .shift = 12, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data) { + .name = "gp1_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_gp1_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_hifi_init_regs[] = { + { .reg = HIFIPLL_CTRL1, .def = 0x00000000 }, + { .reg = HIFIPLL_CTRL2, .def = 0x00000000 }, + { .reg = HIFIPLL_CTRL3, .def = 0x6a285c00 }, + { .reg = HIFIPLL_CTRL4, .def = 0x65771290 }, + { .reg = HIFIPLL_CTRL5, .def = 0x3927200a }, + { .reg = HIFIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap t7_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HIFIPLL_CTRL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HIFIPLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HIFIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_hifi_init_regs, + .init_count = ARRAY_SIZE(t7_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 = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HIFIPLL_CTRL0, + .shift = 16, + .width = 2, + .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 *[]) { + &t7_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The T7 PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + */ +static const struct reg_sequence t7_pcie_pll_init_regs[] = { + { .reg = PCIEPLL_CTRL0, .def = 0x200c04c8 }, + { .reg = PCIEPLL_CTRL0, .def = 0x300c04c8 }, + { .reg = PCIEPLL_CTRL1, .def = 0x30000000 }, + { .reg = PCIEPLL_CTRL2, .def = 0x00001100 }, + { .reg = PCIEPLL_CTRL3, .def = 0x10058e00 }, + { .reg = PCIEPLL_CTRL4, .def = 0x000100c0 }, + { .reg = PCIEPLL_CTRL5, .def = 0x68000048 }, + { .reg = PCIEPLL_CTRL5, .def = 0x68000068, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL4, .def = 0x008100c0, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL0, .def = 0x340c04c8 }, + { .reg = PCIEPLL_CTRL0, .def = 0x140c04c8, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL2, .def = 0x00001000 } +}; + +static struct clk_regmap t7_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = PCIEPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = PCIEPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = PCIEPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = PCIEPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = PCIEPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .init_regs = t7_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(t7_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor t7_pcie_pll_dco_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = PCIEPLL_CTRL0, + .shift = 16, + .width = 5, + /* the divisor is 32 when [16:21] = 0 */ + .flags = CLK_DIVIDER_MAX_AT_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_dco_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_pcie_pll = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_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 = "in0", + }, + .num_parents = 1, + }, +}; + +static const struct reg_sequence t7_mpll0_init_regs[] = { + { .reg = MPLL_CTRL2, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL1, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll0_init_regs, + .init_count = ARRAY_SIZE(t7_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll1_init_regs[] = { + { .reg = MPLL_CTRL4, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL3, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll1_init_regs, + .init_count = ARRAY_SIZE(t7_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll2_init_regs[] = { + { .reg = MPLL_CTRL6, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL5, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll2_init_regs, + .init_count = ARRAY_SIZE(t7_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll3_init_regs[] = { + { .reg = MPLL_CTRL8, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL7, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll3_init_regs, + .init_count = ARRAY_SIZE(t7_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_hdmi_init_regs[] = { + { .reg = HDMIPLL_CTRL1, .def = 0x00000000 }, + { .reg = HDMIPLL_CTRL2, .def = 0x00000000 }, + { .reg = HDMIPLL_CTRL3, .def = 0x6a28dc00 }, + { .reg = HDMIPLL_CTRL4, .def = 0x65771290 }, + { .reg = HDMIPLL_CTRL5, .def = 0x39272000 }, + { .reg = HDMIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap t7_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HDMIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HDMIPLL_CTRL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HDMIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = HDMIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HDMIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_hdmi_init_regs, + .init_count = ARRAY_SIZE(t7_hdmi_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "in0", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HDMIPLL_CTRL0, + .shift = 16, + .width = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HDMIPLL_CTRL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_mult_range t7_mclk_pll_mult_range = { + .min = 67, + .max = 133, +}; + +static const struct reg_sequence t7_mclk_init_regs[] = { + { .reg = MCLK_PLL_CNTL1, .def = 0x1470500f }, + { .reg = MCLK_PLL_CNTL2, .def = 0x00023001 }, + { .reg = MCLK_PLL_CNTL3, .def = 0x18180000 }, + { .reg = MCLK_PLL_CNTL4, .def = 0x00180303 }, +}; + +static struct clk_regmap t7_mclk_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 16, + .width = 5, + }, + .l = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .l_detect = { + .reg_off = MCLK_PLL_CNTL2, + .shift = 6, + .width = 1, + }, + .range = &t7_mclk_pll_mult_range, + .init_regs = t7_mclk_init_regs, + .init_count = ARRAY_SIZE(t7_mclk_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +/* max div is 16 */ +static const struct clk_div_table t7_mclk_div[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { .val = 4, .div = 16 }, + { /* sentinel */ } +}; + +static struct clk_regmap t7_mclk_pre_od = { + .data = &(struct clk_regmap_div_data){ + .offset = MCLK_PLL_CNTL0, + .shift = 12, + .width = 3, + .table = t7_mclk_div, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pre_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = MCLK_PLL_CNTL4, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ONE_BASED, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_pre_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = MCLK_PLL_CNTL4, + .mask = 0x3, + .shift = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &t7_mclk_pll.hw }, + { .fw_name = "in1", }, + { .fw_name = "in2", }, + }, + .num_parents = 3, + }, +}; + +static struct clk_fixed_factor t7_mclk_0_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mclk_0_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mclk_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_0_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_0_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_0_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = MCLK_PLL_CNTL4, + .mask = 0x3, + .shift = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &t7_mclk_pll.hw }, + { .fw_name = "in1", }, + { .fw_name = "in2", }, + }, + .num_parents = 3, + }, +}; + +static struct clk_fixed_factor t7_mclk_1_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mclk_1_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mclk_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_1_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_1_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_1_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_hw *t7_gp0_hw_clks[] = { + [CLKID_GP0_PLL_DCO] = &t7_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &t7_gp0_pll.hw, +}; + +static struct clk_hw *t7_gp1_hw_clks[] = { + [CLKID_GP1_PLL_DCO] = &t7_gp1_pll_dco.hw, + [CLKID_GP1_PLL] = &t7_gp1_pll.hw, +}; + +static struct clk_hw *t7_hifi_hw_clks[] = { + [CLKID_HIFI_PLL_DCO] = &t7_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &t7_hifi_pll.hw, +}; + +static struct clk_hw *t7_pcie_hw_clks[] = { + [CLKID_PCIE_PLL_DCO] = &t7_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &t7_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &t7_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &t7_pcie_pll.hw, +}; + +static struct clk_hw *t7_mpll_hw_clks[] = { + [CLKID_MPLL_PREDIV] = &t7_mpll_prediv.hw, + [CLKID_MPLL0_DIV] = &t7_mpll0_div.hw, + [CLKID_MPLL0] = &t7_mpll0.hw, + [CLKID_MPLL1_DIV] = &t7_mpll1_div.hw, + [CLKID_MPLL1] = &t7_mpll1.hw, + [CLKID_MPLL2_DIV] = &t7_mpll2_div.hw, + [CLKID_MPLL2] = &t7_mpll2.hw, + [CLKID_MPLL3_DIV] = &t7_mpll3_div.hw, + [CLKID_MPLL3] = &t7_mpll3.hw, +}; + +static struct clk_hw *t7_hdmi_hw_clks[] = { + [CLKID_HDMI_PLL_DCO] = &t7_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &t7_hdmi_pll_od.hw, + [CLKID_HDMI_PLL] = &t7_hdmi_pll.hw, +}; + +static struct clk_hw *t7_mclk_hw_clks[] = { + [CLKID_MCLK_PLL_DCO] = &t7_mclk_pll_dco.hw, + [CLKID_MCLK_PRE] = &t7_mclk_pre_od.hw, + [CLKID_MCLK_PLL] = &t7_mclk_pll.hw, + [CLKID_MCLK_0_SEL] = &t7_mclk_0_sel.hw, + [CLKID_MCLK_0_DIV2] = &t7_mclk_0_div2.hw, + [CLKID_MCLK_0_PRE] = &t7_mclk_0_pre.hw, + [CLKID_MCLK_0] = &t7_mclk_0.hw, + [CLKID_MCLK_1_SEL] = &t7_mclk_1_sel.hw, + [CLKID_MCLK_1_DIV2] = &t7_mclk_1_div2.hw, + [CLKID_MCLK_1_PRE] = &t7_mclk_1_pre.hw, + [CLKID_MCLK_1] = &t7_mclk_1.hw, +}; + +static const struct meson_clkc_data t7_gp0_data = { + .hw_clks = { + .hws = t7_gp0_hw_clks, + .num = ARRAY_SIZE(t7_gp0_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_gp1_data = { + .hw_clks = { + .hws = t7_gp1_hw_clks, + .num = ARRAY_SIZE(t7_gp1_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_hifi_data = { + .hw_clks = { + .hws = t7_hifi_hw_clks, + .num = ARRAY_SIZE(t7_hifi_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_pcie_data = { + .hw_clks = { + .hws = t7_pcie_hw_clks, + .num = ARRAY_SIZE(t7_pcie_hw_clks), + }, +}; + +static const struct reg_sequence t7_mpll_init_regs[] = { + { .reg = MPLL_CTRL0, .def = 0x00000543 } +}; + +static const struct meson_clkc_data t7_mpll_data = { + .hw_clks = { + .hws = t7_mpll_hw_clks, + .num = ARRAY_SIZE(t7_mpll_hw_clks), + }, + .init_regs = t7_mpll_init_regs, + .init_count = ARRAY_SIZE(t7_mpll_init_regs), +}; + +static const struct meson_clkc_data t7_hdmi_data = { + .hw_clks = { + .hws = t7_hdmi_hw_clks, + .num = ARRAY_SIZE(t7_hdmi_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_mclk_data = { + .hw_clks = { + .hws = t7_mclk_hw_clks, + .num = ARRAY_SIZE(t7_mclk_hw_clks), + }, +}; + +static const struct of_device_id t7_pll_clkc_match_table[] = { + { .compatible = "amlogic,t7-gp0-pll", .data = &t7_gp0_data, }, + { .compatible = "amlogic,t7-gp1-pll", .data = &t7_gp1_data, }, + { .compatible = "amlogic,t7-hifi-pll", .data = &t7_hifi_data, }, + { .compatible = "amlogic,t7-pcie-pll", .data = &t7_pcie_data, }, + { .compatible = "amlogic,t7-mpll", .data = &t7_mpll_data, }, + { .compatible = "amlogic,t7-hdmi-pll", .data = &t7_hdmi_data, }, + { .compatible = "amlogic,t7-mclk-pll", .data = &t7_mclk_data, }, + {} +}; +MODULE_DEVICE_TABLE(of, t7_pll_clkc_match_table); + +static struct platform_driver t7_pll_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "t7-pll-clkc", + .of_match_table = t7_pll_clkc_match_table, + }, +}; +module_platform_driver(t7_pll_clkc_driver); + +MODULE_DESCRIPTION("Amlogic T7 PLL Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); From fab4d651b592b3ebc836e410ae27b8b832a5bff2 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 12 Dec 2025 10:26:18 +0800 Subject: [PATCH 05/38] clk: meson: t7: add t7 clock peripherals controller driver Add Peripheral clock controller driver for the Amlogic T7 SoC family. Signed-off-by: Jian Hu Link: https://lore.kernel.org/r/20251212022619.3072132-6-jian.hu@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 13 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/t7-peripherals.c | 1271 ++++++++++++++++++++++++++++ 3 files changed, 1285 insertions(+) create mode 100644 drivers/clk/meson/t7-peripherals.c diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index e6a059bcf636..cf8cf3f9e4ee 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -216,4 +216,17 @@ config COMMON_CLK_T7_PLL device, AKA T7. PLLs are required by most peripheral to operate. Say Y if you want T7 PLL clock controller to work. +config COMMON_CLK_T7_PERIPHERALS + tristate "Amlogic T7 SoC peripherals clock controller support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + imply COMMON_CLK_SCMI + imply COMMON_CLK_T7_PLL + help + Support for the peripherals clock controller on Amlogic A311D2 based + device, AKA T7. Peripherals are required by most peripheral to operate. + Say Y if you want T7 peripherals clock controller to work. endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 8e3f7f94c639..c6719694a242 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o +obj-$(CONFIG_COMMON_CLK_T7_PERIPHERALS) += t7-peripherals.o diff --git a/drivers/clk/meson/t7-peripherals.c b/drivers/clk/meson/t7-peripherals.c new file mode 100644 index 000000000000..214db7850d86 --- /dev/null +++ b/drivers/clk/meson/t7-peripherals.c @@ -0,0 +1,1271 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + */ + +#include +#include +#include "clk-dualdiv.h" +#include "clk-regmap.h" +#include "meson-clkc-utils.h" +#include + +#define RTC_BY_OSCIN_CTRL0 0x8 +#define RTC_BY_OSCIN_CTRL1 0xc +#define RTC_CTRL 0x10 +#define SYS_CLK_CTRL0 0x40 +#define SYS_CLK_EN0_REG0 0x44 +#define SYS_CLK_EN0_REG1 0x48 +#define SYS_CLK_EN0_REG2 0x4c +#define SYS_CLK_EN0_REG3 0x50 +#define CECA_CTRL0 0x88 +#define CECA_CTRL1 0x8c +#define CECB_CTRL0 0x90 +#define CECB_CTRL1 0x94 +#define SC_CLK_CTRL 0x98 +#define DSPA_CLK_CTRL0 0x9c +#define DSPB_CLK_CTRL0 0xa0 +#define CLK12_24_CTRL 0xa8 +#define ANAKIN_CLK_CTRL 0xac +#define MIPI_CSI_PHY_CLK_CTRL 0x10c +#define MIPI_ISP_CLK_CTRL 0x110 +#define TS_CLK_CTRL 0x158 +#define MALI_CLK_CTRL 0x15c +#define ETH_CLK_CTRL 0x164 +#define NAND_CLK_CTRL 0x168 +#define SD_EMMC_CLK_CTRL 0x16c +#define SPICC_CLK_CTRL 0x174 +#define SAR_CLK_CTRL0 0x17c +#define PWM_CLK_AB_CTRL 0x180 +#define PWM_CLK_CD_CTRL 0x184 +#define PWM_CLK_EF_CTRL 0x188 +#define PWM_CLK_AO_AB_CTRL 0x1a0 +#define PWM_CLK_AO_CD_CTRL 0x1a4 +#define PWM_CLK_AO_EF_CTRL 0x1a8 +#define PWM_CLK_AO_GH_CTRL 0x1ac +#define SPICC_CLK_CTRL1 0x1c0 +#define SPICC_CLK_CTRL2 0x1c4 + +#define T7_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(t7_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define T7_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(t7_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define T7_COMP_GATE(_name, _reg, _bit, _iflags) \ + MESON_COMP_GATE(t7_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags)) + +static struct clk_regmap t7_rtc_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_duandiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param t7_dualdiv_table[] = { + { + .n1 = 733, .m1 = 8, + .n2 = 732, .m2 = 11, + .dual = 1, + }, + {} +}; + +static struct clk_regmap t7_rtc_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_rtc_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_div.hw, + &t7_rtc_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_rtc_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_rtc = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_CTRL, + .mask = 0x3, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc", + .ops = &clk_regmap_mux_ops, + /* + * xtal is also on parent input #3 but that it is not useful to CCF since + * the same parent is available with parent input #0 + */ + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &t7_rtc_dualdiv.hw }, + { .fw_name = "ext_rtc", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ceca_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECA_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECA_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECA_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECA_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECA_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_div.hw, + &t7_ceca_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_ceca = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CTRL1, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv.hw, + &t7_rtc.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "cecb_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECB_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECB_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECB_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECB_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECB_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_div.hw, + &t7_cecb_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CTRL1, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv.hw, + &t7_rtc.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_sc_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "xtal", }, +}; + +static T7_COMP_SEL(sc, SC_CLK_CTRL, 9, 0x3, t7_sc_parents); +static T7_COMP_DIV(sc, SC_CLK_CTRL, 0, 8); +static T7_COMP_GATE(sc, SC_CLK_CTRL, 8, 0); + +static const struct clk_parent_data t7_dsp_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "hifi", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv7", }, + { .hw = &t7_rtc.hw }, +}; + +static T7_COMP_SEL(dspa_0, DSPA_CLK_CTRL0, 10, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspa_0, DSPA_CLK_CTRL0, 0, 10); +static T7_COMP_GATE(dspa_0, DSPA_CLK_CTRL0, 13, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(dspa_1, DSPA_CLK_CTRL0, 26, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspa_1, DSPA_CLK_CTRL0, 16, 10); +static T7_COMP_GATE(dspa_1, DSPA_CLK_CTRL0, 29, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_dspa = { + .data = &(struct clk_regmap_mux_data){ + .offset = 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 *[]) { + &t7_dspa_0.hw, + &t7_dspa_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static T7_COMP_SEL(dspb_0, DSPB_CLK_CTRL0, 10, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspb_0, DSPB_CLK_CTRL0, 0, 10); +static T7_COMP_GATE(dspb_0, DSPB_CLK_CTRL0, 13, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(dspb_1, DSPB_CLK_CTRL0, 26, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspb_1, DSPB_CLK_CTRL0, 16, 10); +static T7_COMP_GATE(dspb_1, DSPB_CLK_CTRL0, 29, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_dspb = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPB_CLK_CTRL0, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_dspb_0.hw, + &t7_dspb_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_24m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "24m", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor t7_24m_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "24m_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_24m.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_12m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "12m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_24m_div2.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_25m_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLK12_24_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "25m_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_25m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "25m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_25m_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_anakin_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "vid_pll0", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "fdiv2p5", }, +}; + +static T7_COMP_SEL(anakin_0, ANAKIN_CLK_CTRL, 9, 0x7, t7_anakin_parents); +static T7_COMP_DIV(anakin_0, ANAKIN_CLK_CTRL, 0, 7); +static T7_COMP_GATE(anakin_0, ANAKIN_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(anakin_1, ANAKIN_CLK_CTRL, 25, 0x7, t7_anakin_parents); +static T7_COMP_DIV(anakin_1, ANAKIN_CLK_CTRL, 16, 7); +static T7_COMP_GATE(anakin_1, ANAKIN_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_anakin_01_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = ANAKIN_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "anakin_01_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_anakin_0.hw, + &t7_anakin_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT + }, +}; + +static struct clk_regmap t7_anakin = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANAKIN_CLK_CTRL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "anakin", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_anakin_01_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT + }, +}; + +static const struct clk_parent_data t7_mipi_csi_phy_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp1", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, +}; + +static T7_COMP_SEL(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7, t7_mipi_csi_phy_parents); +static T7_COMP_DIV(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 25, 0x7, t7_mipi_csi_phy_parents); +static T7_COMP_DIV(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 16, 7); +static T7_COMP_GATE(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_mipi_csi_phy = { + .data = &(struct clk_regmap_mux_data){ + .offset = MIPI_CSI_PHY_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_csi_phy", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mipi_csi_phy_0.hw, + &t7_mipi_csi_phy_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_mipi_isp_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp1", }, +}; + +static T7_COMP_SEL(mipi_isp, MIPI_ISP_CLK_CTRL, 9, 0x7, t7_mipi_isp_parents); +static T7_COMP_DIV(mipi_isp, MIPI_ISP_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mipi_isp, MIPI_ISP_CLK_CTRL, 8, 0); + +static struct clk_regmap t7_ts_div = { + .data = &(struct clk_regmap_div_data){ + .offset = TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ts = { + .data = &(struct clk_regmap_gate_data){ + .offset = TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ts_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_mali_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp0", }, + { .fw_name = "gp1", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, +}; + +static T7_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, t7_mali_parents); +static T7_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, t7_mali_parents); +static T7_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7); +static T7_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = MALI_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mali_0.hw, + &t7_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * parent index 2, 3, 4, 5, 6 not connect any clock signal, + * the last parent connect external PAD + */ +static u32 t7_eth_rmii_parents_val_table[] = { 0, 1, 7 }; +static const struct clk_parent_data t7_eth_rmii_parents[] = { + { .fw_name = "fdiv2", }, + { .fw_name = "gp1", }, + { .fw_name = "ext_rmii", }, +}; + +static struct clk_regmap t7_eth_rmii_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = ETH_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .table = t7_eth_rmii_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = t7_eth_rmii_parents, + .num_parents = ARRAY_SIZE(t7_eth_rmii_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap t7_eth_rmii_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ETH_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_eth_rmii_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_eth_rmii = { + .data = &(struct clk_regmap_gate_data) { + .offset = 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 *[]) { + &t7_eth_rmii_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_fdiv2_div8 = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data){ + .name = "fdiv2_div8", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fdiv2", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_eth_125m = { + .data = &(struct clk_regmap_gate_data) { + .offset = 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 *[]) { + &t7_fdiv2_div8.hw + }, + .num_parents = 1, + }, +}; + +static const struct clk_parent_data t7_sd_emmc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "hifi", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp0", }, +}; + +static T7_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7); +static T7_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7, 0); + +static T7_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7); +static T7_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23, 0); + +static T7_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7); +static T7_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7, 0); + +static const struct clk_parent_data t7_spicc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "gp1", }, +}; + +static T7_COMP_SEL(spicc0, SPICC_CLK_CTRL, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc0, SPICC_CLK_CTRL, 0, 6); +static T7_COMP_GATE(spicc0, SPICC_CLK_CTRL, 6, 0); + +static T7_COMP_SEL(spicc1, SPICC_CLK_CTRL, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc1, SPICC_CLK_CTRL, 16, 6); +static T7_COMP_GATE(spicc1, SPICC_CLK_CTRL, 22, 0); + +static T7_COMP_SEL(spicc2, SPICC_CLK_CTRL1, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc2, SPICC_CLK_CTRL1, 0, 6); +static T7_COMP_GATE(spicc2, SPICC_CLK_CTRL1, 6, 0); + +static T7_COMP_SEL(spicc3, SPICC_CLK_CTRL1, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc3, SPICC_CLK_CTRL1, 16, 6); +static T7_COMP_GATE(spicc3, SPICC_CLK_CTRL1, 22, 0); + +static T7_COMP_SEL(spicc4, SPICC_CLK_CTRL2, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc4, SPICC_CLK_CTRL2, 0, 6); +static T7_COMP_GATE(spicc4, SPICC_CLK_CTRL2, 6, 0); + +static T7_COMP_SEL(spicc5, SPICC_CLK_CTRL2, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc5, SPICC_CLK_CTRL2, 16, 6); +static T7_COMP_GATE(spicc5, SPICC_CLK_CTRL2, 22, 0); + +static const struct clk_parent_data t7_saradc_parents[] = { + { .fw_name = "xtal" }, + { .fw_name = "sys" }, +}; + +static T7_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, t7_saradc_parents); +static T7_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8); +static T7_COMP_GATE(saradc, SAR_CLK_CTRL0, 8, 0); + +static const struct clk_parent_data t7_pwm_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "vid_pll0", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, +}; + +static T7_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8); +static T7_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8); +static T7_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8); +static T7_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8); +static T7_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8); +static T7_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8); +static T7_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 24, 0); + +static const struct clk_parent_data t7_sys_pclk_parents = { .fw_name = "sys" }; + +#define T7_SYS_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(t7_##_name, _reg, _bit, &t7_sys_pclk_parents, _flags) + +static T7_SYS_PCLK(sys_ddr, SYS_CLK_EN0_REG0, 0, 0); +static T7_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1, 0); +static T7_SYS_PCLK(sys_mipi_dsi_a, SYS_CLK_EN0_REG0, 2, 0); +static T7_SYS_PCLK(sys_mipi_dsi_b, SYS_CLK_EN0_REG0, 3, 0); +static T7_SYS_PCLK(sys_ethphy, SYS_CLK_EN0_REG0, 4, 0); +static T7_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6, 0); +static T7_SYS_PCLK(sys_aocpu, SYS_CLK_EN0_REG0, 13, 0); +static T7_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14, 0); +static T7_SYS_PCLK(sys_cec, SYS_CLK_EN0_REG0, 16, 0); +static T7_SYS_PCLK(sys_gdc, SYS_CLK_EN0_REG0, 17, 0); +static T7_SYS_PCLK(sys_deswarp, SYS_CLK_EN0_REG0, 18, 0); +static T7_SYS_PCLK(sys_ampipe_nand, SYS_CLK_EN0_REG0, 19, 0); +static T7_SYS_PCLK(sys_ampipe_eth, SYS_CLK_EN0_REG0, 20, 0); +static T7_SYS_PCLK(sys_am2axi0, SYS_CLK_EN0_REG0, 21, 0); +static T7_SYS_PCLK(sys_am2axi1, SYS_CLK_EN0_REG0, 22, 0); +static T7_SYS_PCLK(sys_am2axi2, SYS_CLK_EN0_REG0, 23, 0); +static T7_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24, 0); +static T7_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25, 0); +static T7_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26, 0); +static T7_SYS_PCLK(sys_smartcard, SYS_CLK_EN0_REG0, 27, 0); +static T7_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28, 0); +static T7_SYS_PCLK(sys_spifc, SYS_CLK_EN0_REG0, 29, 0); +static T7_SYS_PCLK(sys_msr_clk, SYS_CLK_EN0_REG0, 30, 0); +static T7_SYS_PCLK(sys_ir_ctrl, SYS_CLK_EN0_REG0, 31, 0); +static T7_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0, 0); +static T7_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3, 0); +static T7_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5, 0); +static T7_SYS_PCLK(sys_uart_b, SYS_CLK_EN0_REG1, 6, 0); +static T7_SYS_PCLK(sys_uart_c, SYS_CLK_EN0_REG1, 7, 0); +static T7_SYS_PCLK(sys_uart_d, SYS_CLK_EN0_REG1, 8, 0); +static T7_SYS_PCLK(sys_uart_e, SYS_CLK_EN0_REG1, 9, 0); +static T7_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10, 0); +static T7_SYS_PCLK(sys_aififo, SYS_CLK_EN0_REG1, 11, 0); +static T7_SYS_PCLK(sys_spicc2, SYS_CLK_EN0_REG1, 12, 0); +static T7_SYS_PCLK(sys_spicc3, SYS_CLK_EN0_REG1, 13, 0); +static T7_SYS_PCLK(sys_spicc4, SYS_CLK_EN0_REG1, 14, 0); +static T7_SYS_PCLK(sys_ts_a73, SYS_CLK_EN0_REG1, 15, 0); +static T7_SYS_PCLK(sys_ts_a53, SYS_CLK_EN0_REG1, 16, 0); +static T7_SYS_PCLK(sys_spicc5, SYS_CLK_EN0_REG1, 17, 0); +static T7_SYS_PCLK(sys_g2d, SYS_CLK_EN0_REG1, 20, 0); +static T7_SYS_PCLK(sys_spicc0, SYS_CLK_EN0_REG1, 21, 0); +static T7_SYS_PCLK(sys_spicc1, SYS_CLK_EN0_REG1, 22, 0); +static T7_SYS_PCLK(sys_pcie, SYS_CLK_EN0_REG1, 24, 0); +static T7_SYS_PCLK(sys_usb, SYS_CLK_EN0_REG1, 26, 0); +static T7_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27, 0); +static T7_SYS_PCLK(sys_i2c_ao_a, SYS_CLK_EN0_REG1, 28, 0); +static T7_SYS_PCLK(sys_i2c_ao_b, SYS_CLK_EN0_REG1, 29, 0); +static T7_SYS_PCLK(sys_i2c_m_a, SYS_CLK_EN0_REG1, 30, 0); +static T7_SYS_PCLK(sys_i2c_m_b, SYS_CLK_EN0_REG1, 31, 0); +static T7_SYS_PCLK(sys_i2c_m_c, SYS_CLK_EN0_REG2, 0, 0); +static T7_SYS_PCLK(sys_i2c_m_d, SYS_CLK_EN0_REG2, 1, 0); +static T7_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2, 0); +static T7_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3, 0); +static T7_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4, 0); +static T7_SYS_PCLK(sys_i2c_s_a, SYS_CLK_EN0_REG2, 5, 0); +static T7_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG2, 8, 0); +static T7_SYS_PCLK(sys_mmc_apb, SYS_CLK_EN0_REG2, 11, 0); +static T7_SYS_PCLK(sys_mipi_isp_pclk, SYS_CLK_EN0_REG2, 17, 0); +static T7_SYS_PCLK(sys_rsa, SYS_CLK_EN0_REG2, 18, 0); +static T7_SYS_PCLK(sys_pclk_sys_apb, SYS_CLK_EN0_REG2, 19, 0); +static T7_SYS_PCLK(sys_a73pclk_apb, SYS_CLK_EN0_REG2, 20, 0); +static T7_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21, 0); +static T7_SYS_PCLK(sys_dspb, SYS_CLK_EN0_REG2, 22, 0); +static T7_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25, 0); +static T7_SYS_PCLK(sys_sar_adc, SYS_CLK_EN0_REG2, 28, 0); +/* + * 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 T7_SYS_PCLK(sys_gic, SYS_CLK_EN0_REG2, 30, CLK_IS_CRITICAL); +static T7_SYS_PCLK(sys_ts_gpu, SYS_CLK_EN0_REG2, 31, 0); +static T7_SYS_PCLK(sys_ts_nna, SYS_CLK_EN0_REG3, 0, 0); +static T7_SYS_PCLK(sys_ts_vpu, SYS_CLK_EN0_REG3, 1, 0); +static T7_SYS_PCLK(sys_ts_hevc, SYS_CLK_EN0_REG3, 2, 0); +static T7_SYS_PCLK(sys_pwm_ao_ab, SYS_CLK_EN0_REG3, 3, 0); +static T7_SYS_PCLK(sys_pwm_ao_cd, SYS_CLK_EN0_REG3, 4, 0); +static T7_SYS_PCLK(sys_pwm_ao_ef, SYS_CLK_EN0_REG3, 5, 0); +static T7_SYS_PCLK(sys_pwm_ao_gh, SYS_CLK_EN0_REG3, 6, 0); +static T7_SYS_PCLK(sys_pwm_ab, SYS_CLK_EN0_REG3, 7, 0); +static T7_SYS_PCLK(sys_pwm_cd, SYS_CLK_EN0_REG3, 8, 0); +static T7_SYS_PCLK(sys_pwm_ef, SYS_CLK_EN0_REG3, 9, 0); + +/* Array of all clocks registered by this provider */ +static struct clk_hw *t7_peripherals_hw_clks[] = { + [CLKID_RTC_DUALDIV_IN] = &t7_rtc_dualdiv_in.hw, + [CLKID_RTC_DUALDIV_DIV] = &t7_rtc_dualdiv_div.hw, + [CLKID_RTC_DUALDIV_SEL] = &t7_rtc_dualdiv_sel.hw, + [CLKID_RTC_DUALDIV] = &t7_rtc_dualdiv.hw, + [CLKID_RTC] = &t7_rtc.hw, + [CLKID_CECA_DUALDIV_IN] = &t7_ceca_dualdiv_in.hw, + [CLKID_CECA_DUALDIV_DIV] = &t7_ceca_dualdiv_div.hw, + [CLKID_CECA_DUALDIV_SEL] = &t7_ceca_dualdiv_sel.hw, + [CLKID_CECA_DUALDIV] = &t7_ceca_dualdiv.hw, + [CLKID_CECA] = &t7_ceca.hw, + [CLKID_CECB_DUALDIV_IN] = &t7_cecb_dualdiv_in.hw, + [CLKID_CECB_DUALDIV_DIV] = &t7_cecb_dualdiv_div.hw, + [CLKID_CECB_DUALDIV_SEL] = &t7_cecb_dualdiv_sel.hw, + [CLKID_CECB_DUALDIV] = &t7_cecb_dualdiv.hw, + [CLKID_CECB] = &t7_cecb.hw, + [CLKID_SC_SEL] = &t7_sc_sel.hw, + [CLKID_SC_DIV] = &t7_sc_div.hw, + [CLKID_SC] = &t7_sc.hw, + [CLKID_DSPA_0_SEL] = &t7_dspa_0_sel.hw, + [CLKID_DSPA_0_DIV] = &t7_dspa_0_div.hw, + [CLKID_DSPA_0] = &t7_dspa_0.hw, + [CLKID_DSPA_1_SEL] = &t7_dspa_1_sel.hw, + [CLKID_DSPA_1_DIV] = &t7_dspa_1_div.hw, + [CLKID_DSPA_1] = &t7_dspa_1.hw, + [CLKID_DSPA] = &t7_dspa.hw, + [CLKID_DSPB_0_SEL] = &t7_dspb_0_sel.hw, + [CLKID_DSPB_0_DIV] = &t7_dspb_0_div.hw, + [CLKID_DSPB_0] = &t7_dspb_0.hw, + [CLKID_DSPB_1_SEL] = &t7_dspb_1_sel.hw, + [CLKID_DSPB_1_DIV] = &t7_dspb_1_div.hw, + [CLKID_DSPB_1] = &t7_dspb_1.hw, + [CLKID_DSPB] = &t7_dspb.hw, + [CLKID_24M] = &t7_24m.hw, + [CLKID_24M_DIV2] = &t7_24m_div2.hw, + [CLKID_12M] = &t7_12m.hw, + [CLKID_25M_DIV] = &t7_25m_div.hw, + [CLKID_25M] = &t7_25m.hw, + [CLKID_ANAKIN_0_SEL] = &t7_anakin_0_sel.hw, + [CLKID_ANAKIN_0_DIV] = &t7_anakin_0_div.hw, + [CLKID_ANAKIN_0] = &t7_anakin_0.hw, + [CLKID_ANAKIN_1_SEL] = &t7_anakin_1_sel.hw, + [CLKID_ANAKIN_1_DIV] = &t7_anakin_1_div.hw, + [CLKID_ANAKIN_1] = &t7_anakin_1.hw, + [CLKID_ANAKIN_01_SEL] = &t7_anakin_01_sel.hw, + [CLKID_ANAKIN] = &t7_anakin.hw, + [CLKID_MIPI_CSI_PHY_0_SEL] = &t7_mipi_csi_phy_0_sel.hw, + [CLKID_MIPI_CSI_PHY_0_DIV] = &t7_mipi_csi_phy_0_div.hw, + [CLKID_MIPI_CSI_PHY_0] = &t7_mipi_csi_phy_0.hw, + [CLKID_MIPI_CSI_PHY_1_SEL] = &t7_mipi_csi_phy_1_sel.hw, + [CLKID_MIPI_CSI_PHY_1_DIV] = &t7_mipi_csi_phy_1_div.hw, + [CLKID_MIPI_CSI_PHY_1] = &t7_mipi_csi_phy_1.hw, + [CLKID_MIPI_CSI_PHY] = &t7_mipi_csi_phy.hw, + [CLKID_MIPI_ISP_SEL] = &t7_mipi_isp_sel.hw, + [CLKID_MIPI_ISP_DIV] = &t7_mipi_isp_div.hw, + [CLKID_MIPI_ISP] = &t7_mipi_isp.hw, + [CLKID_TS_DIV] = &t7_ts_div.hw, + [CLKID_TS] = &t7_ts.hw, + [CLKID_MALI_0_SEL] = &t7_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &t7_mali_0_div.hw, + [CLKID_MALI_0] = &t7_mali_0.hw, + [CLKID_MALI_1_SEL] = &t7_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &t7_mali_1_div.hw, + [CLKID_MALI_1] = &t7_mali_1.hw, + [CLKID_MALI] = &t7_mali.hw, + [CLKID_ETH_RMII_SEL] = &t7_eth_rmii_sel.hw, + [CLKID_ETH_RMII_DIV] = &t7_eth_rmii_div.hw, + [CLKID_ETH_RMII] = &t7_eth_rmii.hw, + [CLKID_FCLK_DIV2_DIV8] = &t7_fdiv2_div8.hw, + [CLKID_ETH_125M] = &t7_eth_125m.hw, + [CLKID_SD_EMMC_A_SEL] = &t7_sd_emmc_a_sel.hw, + [CLKID_SD_EMMC_A_DIV] = &t7_sd_emmc_a_div.hw, + [CLKID_SD_EMMC_A] = &t7_sd_emmc_a.hw, + [CLKID_SD_EMMC_B_SEL] = &t7_sd_emmc_b_sel.hw, + [CLKID_SD_EMMC_B_DIV] = &t7_sd_emmc_b_div.hw, + [CLKID_SD_EMMC_B] = &t7_sd_emmc_b.hw, + [CLKID_SD_EMMC_C_SEL] = &t7_sd_emmc_c_sel.hw, + [CLKID_SD_EMMC_C_DIV] = &t7_sd_emmc_c_div.hw, + [CLKID_SD_EMMC_C] = &t7_sd_emmc_c.hw, + [CLKID_SPICC0_SEL] = &t7_spicc0_sel.hw, + [CLKID_SPICC0_DIV] = &t7_spicc0_div.hw, + [CLKID_SPICC0] = &t7_spicc0.hw, + [CLKID_SPICC1_SEL] = &t7_spicc1_sel.hw, + [CLKID_SPICC1_DIV] = &t7_spicc1_div.hw, + [CLKID_SPICC1] = &t7_spicc1.hw, + [CLKID_SPICC2_SEL] = &t7_spicc2_sel.hw, + [CLKID_SPICC2_DIV] = &t7_spicc2_div.hw, + [CLKID_SPICC2] = &t7_spicc2.hw, + [CLKID_SPICC3_SEL] = &t7_spicc3_sel.hw, + [CLKID_SPICC3_DIV] = &t7_spicc3_div.hw, + [CLKID_SPICC3] = &t7_spicc3.hw, + [CLKID_SPICC4_SEL] = &t7_spicc4_sel.hw, + [CLKID_SPICC4_DIV] = &t7_spicc4_div.hw, + [CLKID_SPICC4] = &t7_spicc4.hw, + [CLKID_SPICC5_SEL] = &t7_spicc5_sel.hw, + [CLKID_SPICC5_DIV] = &t7_spicc5_div.hw, + [CLKID_SPICC5] = &t7_spicc5.hw, + [CLKID_SARADC_SEL] = &t7_saradc_sel.hw, + [CLKID_SARADC_DIV] = &t7_saradc_div.hw, + [CLKID_SARADC] = &t7_saradc.hw, + [CLKID_PWM_A_SEL] = &t7_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &t7_pwm_a_div.hw, + [CLKID_PWM_A] = &t7_pwm_a.hw, + [CLKID_PWM_B_SEL] = &t7_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &t7_pwm_b_div.hw, + [CLKID_PWM_B] = &t7_pwm_b.hw, + [CLKID_PWM_C_SEL] = &t7_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &t7_pwm_c_div.hw, + [CLKID_PWM_C] = &t7_pwm_c.hw, + [CLKID_PWM_D_SEL] = &t7_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &t7_pwm_d_div.hw, + [CLKID_PWM_D] = &t7_pwm_d.hw, + [CLKID_PWM_E_SEL] = &t7_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &t7_pwm_e_div.hw, + [CLKID_PWM_E] = &t7_pwm_e.hw, + [CLKID_PWM_F_SEL] = &t7_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &t7_pwm_f_div.hw, + [CLKID_PWM_F] = &t7_pwm_f.hw, + [CLKID_PWM_AO_A_SEL] = &t7_pwm_ao_a_sel.hw, + [CLKID_PWM_AO_A_DIV] = &t7_pwm_ao_a_div.hw, + [CLKID_PWM_AO_A] = &t7_pwm_ao_a.hw, + [CLKID_PWM_AO_B_SEL] = &t7_pwm_ao_b_sel.hw, + [CLKID_PWM_AO_B_DIV] = &t7_pwm_ao_b_div.hw, + [CLKID_PWM_AO_B] = &t7_pwm_ao_b.hw, + [CLKID_PWM_AO_C_SEL] = &t7_pwm_ao_c_sel.hw, + [CLKID_PWM_AO_C_DIV] = &t7_pwm_ao_c_div.hw, + [CLKID_PWM_AO_C] = &t7_pwm_ao_c.hw, + [CLKID_PWM_AO_D_SEL] = &t7_pwm_ao_d_sel.hw, + [CLKID_PWM_AO_D_DIV] = &t7_pwm_ao_d_div.hw, + [CLKID_PWM_AO_D] = &t7_pwm_ao_d.hw, + [CLKID_PWM_AO_E_SEL] = &t7_pwm_ao_e_sel.hw, + [CLKID_PWM_AO_E_DIV] = &t7_pwm_ao_e_div.hw, + [CLKID_PWM_AO_E] = &t7_pwm_ao_e.hw, + [CLKID_PWM_AO_F_SEL] = &t7_pwm_ao_f_sel.hw, + [CLKID_PWM_AO_F_DIV] = &t7_pwm_ao_f_div.hw, + [CLKID_PWM_AO_F] = &t7_pwm_ao_f.hw, + [CLKID_PWM_AO_G_SEL] = &t7_pwm_ao_g_sel.hw, + [CLKID_PWM_AO_G_DIV] = &t7_pwm_ao_g_div.hw, + [CLKID_PWM_AO_G] = &t7_pwm_ao_g.hw, + [CLKID_PWM_AO_H_SEL] = &t7_pwm_ao_h_sel.hw, + [CLKID_PWM_AO_H_DIV] = &t7_pwm_ao_h_div.hw, + [CLKID_PWM_AO_H] = &t7_pwm_ao_h.hw, + [CLKID_SYS_DDR] = &t7_sys_ddr.hw, + [CLKID_SYS_DOS] = &t7_sys_dos.hw, + [CLKID_SYS_MIPI_DSI_A] = &t7_sys_mipi_dsi_a.hw, + [CLKID_SYS_MIPI_DSI_B] = &t7_sys_mipi_dsi_b.hw, + [CLKID_SYS_ETHPHY] = &t7_sys_ethphy.hw, + [CLKID_SYS_MALI] = &t7_sys_mali.hw, + [CLKID_SYS_AOCPU] = &t7_sys_aocpu.hw, + [CLKID_SYS_AUCPU] = &t7_sys_aucpu.hw, + [CLKID_SYS_CEC] = &t7_sys_cec.hw, + [CLKID_SYS_GDC] = &t7_sys_gdc.hw, + [CLKID_SYS_DESWARP] = &t7_sys_deswarp.hw, + [CLKID_SYS_AMPIPE_NAND] = &t7_sys_ampipe_nand.hw, + [CLKID_SYS_AMPIPE_ETH] = &t7_sys_ampipe_eth.hw, + [CLKID_SYS_AM2AXI0] = &t7_sys_am2axi0.hw, + [CLKID_SYS_AM2AXI1] = &t7_sys_am2axi1.hw, + [CLKID_SYS_AM2AXI2] = &t7_sys_am2axi2.hw, + [CLKID_SYS_SD_EMMC_A] = &t7_sys_sd_emmc_a.hw, + [CLKID_SYS_SD_EMMC_B] = &t7_sys_sd_emmc_b.hw, + [CLKID_SYS_SD_EMMC_C] = &t7_sys_sd_emmc_c.hw, + [CLKID_SYS_SMARTCARD] = &t7_sys_smartcard.hw, + [CLKID_SYS_ACODEC] = &t7_sys_acodec.hw, + [CLKID_SYS_SPIFC] = &t7_sys_spifc.hw, + [CLKID_SYS_MSR_CLK] = &t7_sys_msr_clk.hw, + [CLKID_SYS_IR_CTRL] = &t7_sys_ir_ctrl.hw, + [CLKID_SYS_AUDIO] = &t7_sys_audio.hw, + [CLKID_SYS_ETH] = &t7_sys_eth.hw, + [CLKID_SYS_UART_A] = &t7_sys_uart_a.hw, + [CLKID_SYS_UART_B] = &t7_sys_uart_b.hw, + [CLKID_SYS_UART_C] = &t7_sys_uart_c.hw, + [CLKID_SYS_UART_D] = &t7_sys_uart_d.hw, + [CLKID_SYS_UART_E] = &t7_sys_uart_e.hw, + [CLKID_SYS_UART_F] = &t7_sys_uart_f.hw, + [CLKID_SYS_AIFIFO] = &t7_sys_aififo.hw, + [CLKID_SYS_SPICC2] = &t7_sys_spicc2.hw, + [CLKID_SYS_SPICC3] = &t7_sys_spicc3.hw, + [CLKID_SYS_SPICC4] = &t7_sys_spicc4.hw, + [CLKID_SYS_TS_A73] = &t7_sys_ts_a73.hw, + [CLKID_SYS_TS_A53] = &t7_sys_ts_a53.hw, + [CLKID_SYS_SPICC5] = &t7_sys_spicc5.hw, + [CLKID_SYS_G2D] = &t7_sys_g2d.hw, + [CLKID_SYS_SPICC0] = &t7_sys_spicc0.hw, + [CLKID_SYS_SPICC1] = &t7_sys_spicc1.hw, + [CLKID_SYS_PCIE] = &t7_sys_pcie.hw, + [CLKID_SYS_USB] = &t7_sys_usb.hw, + [CLKID_SYS_PCIE_PHY] = &t7_sys_pcie_phy.hw, + [CLKID_SYS_I2C_AO_A] = &t7_sys_i2c_ao_a.hw, + [CLKID_SYS_I2C_AO_B] = &t7_sys_i2c_ao_b.hw, + [CLKID_SYS_I2C_M_A] = &t7_sys_i2c_m_a.hw, + [CLKID_SYS_I2C_M_B] = &t7_sys_i2c_m_b.hw, + [CLKID_SYS_I2C_M_C] = &t7_sys_i2c_m_c.hw, + [CLKID_SYS_I2C_M_D] = &t7_sys_i2c_m_d.hw, + [CLKID_SYS_I2C_M_E] = &t7_sys_i2c_m_e.hw, + [CLKID_SYS_I2C_M_F] = &t7_sys_i2c_m_f.hw, + [CLKID_SYS_HDMITX_APB] = &t7_sys_hdmitx_apb.hw, + [CLKID_SYS_I2C_S_A] = &t7_sys_i2c_s_a.hw, + [CLKID_SYS_HDMIRX_PCLK] = &t7_sys_hdmirx_pclk.hw, + [CLKID_SYS_MMC_APB] = &t7_sys_mmc_apb.hw, + [CLKID_SYS_MIPI_ISP_PCLK] = &t7_sys_mipi_isp_pclk.hw, + [CLKID_SYS_RSA] = &t7_sys_rsa.hw, + [CLKID_SYS_PCLK_SYS_APB] = &t7_sys_pclk_sys_apb.hw, + [CLKID_SYS_A73PCLK_APB] = &t7_sys_a73pclk_apb.hw, + [CLKID_SYS_DSPA] = &t7_sys_dspa.hw, + [CLKID_SYS_DSPB] = &t7_sys_dspb.hw, + [CLKID_SYS_VPU_INTR] = &t7_sys_vpu_intr.hw, + [CLKID_SYS_SAR_ADC] = &t7_sys_sar_adc.hw, + [CLKID_SYS_GIC] = &t7_sys_gic.hw, + [CLKID_SYS_TS_GPU] = &t7_sys_ts_gpu.hw, + [CLKID_SYS_TS_NNA] = &t7_sys_ts_nna.hw, + [CLKID_SYS_TS_VPU] = &t7_sys_ts_vpu.hw, + [CLKID_SYS_TS_HEVC] = &t7_sys_ts_hevc.hw, + [CLKID_SYS_PWM_AO_AB] = &t7_sys_pwm_ao_ab.hw, + [CLKID_SYS_PWM_AO_CD] = &t7_sys_pwm_ao_cd.hw, + [CLKID_SYS_PWM_AO_EF] = &t7_sys_pwm_ao_ef.hw, + [CLKID_SYS_PWM_AO_GH] = &t7_sys_pwm_ao_gh.hw, + [CLKID_SYS_PWM_AB] = &t7_sys_pwm_ab.hw, + [CLKID_SYS_PWM_CD] = &t7_sys_pwm_cd.hw, + [CLKID_SYS_PWM_EF] = &t7_sys_pwm_ef.hw, +}; + +static const struct meson_clkc_data t7_peripherals_data = { + .hw_clks = { + .hws = t7_peripherals_hw_clks, + .num = ARRAY_SIZE(t7_peripherals_hw_clks), + }, +}; + +static const struct of_device_id t7_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,t7-peripherals-clkc", + .data = &t7_peripherals_data + }, + {} +}; +MODULE_DEVICE_TABLE(of, t7_peripherals_clkc_match_table); + +static struct platform_driver t7_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "t7-peripherals-clkc", + .of_match_table = t7_peripherals_clkc_match_table, + }, +}; +module_platform_driver(t7_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic T7 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); From 29c4f32095d01ec570b05141d20945f22d50da26 Mon Sep 17 00:00:00 2001 From: Chuan Liu Date: Fri, 19 Sep 2025 13:58:59 +0800 Subject: [PATCH 06/38] dt-bindings: clock: add video clock indices for Amlogic S4 SoC Add indices for video encoder, demodulator and CVBS clocks. Acked-by: Rob Herring (Arm) Acked-by: Krzysztof Kozlowski Acked-by: Conor Dooley Signed-off-by: Chuan Liu Link: https://lore.kernel.org/r/20250919-add_video_clk-v6-1-fe223161fb3f@amlogic.com Signed-off-by: Jerome Brunet --- .../dt-bindings/clock/amlogic,s4-peripherals-clkc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h index 861a331963ac..b0fc549f53e3 100644 --- a/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h +++ b/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h @@ -232,5 +232,16 @@ #define CLKID_HDCP22_SKPCLK_SEL 222 #define CLKID_HDCP22_SKPCLK_DIV 223 #define CLKID_HDCP22_SKPCLK 224 +#define CLKID_CTS_ENCL_SEL 225 +#define CLKID_CTS_ENCL 226 +#define CLKID_CDAC_SEL 227 +#define CLKID_CDAC_DIV 228 +#define CLKID_CDAC 229 +#define CLKID_DEMOD_CORE_SEL 230 +#define CLKID_DEMOD_CORE_DIV 231 +#define CLKID_DEMOD_CORE 232 +#define CLKID_ADC_EXTCLK_IN_SEL 233 +#define CLKID_ADC_EXTCLK_IN_DIV 234 +#define CLKID_ADC_EXTCLK_IN 235 #endif /* _DT_BINDINGS_CLOCK_AMLOGIC_S4_PERIPHERALS_CLKC_H */ From c78c9dbe2bb950939b3a1fe171c40cfba4f8c520 Mon Sep 17 00:00:00 2001 From: Chuan Liu Date: Fri, 19 Sep 2025 13:59:00 +0800 Subject: [PATCH 07/38] clk: amlogic: add video-related clocks for S4 SoC Add video encoder, demodulator and CVBS clocks. Signed-off-by: Chuan Liu Link: https://lore.kernel.org/r/20250919-add_video_clk-v6-2-fe223161fb3f@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/s4-peripherals.c | 202 +++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index 6d69b132d1e1..aa500ea8ef9c 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -44,6 +44,7 @@ #define CLKCTRL_VDIN_MEAS_CLK_CTRL 0x0f8 #define CLKCTRL_VAPBCLK_CTRL 0x0fc #define CLKCTRL_HDCP22_CTRL 0x100 +#define CLKCTRL_CDAC_CLK_CTRL 0x108 #define CLKCTRL_VDEC_CLK_CTRL 0x140 #define CLKCTRL_VDEC2_CLK_CTRL 0x144 #define CLKCTRL_VDEC3_CLK_CTRL 0x148 @@ -1126,6 +1127,21 @@ static struct clk_regmap s4_cts_encp_sel = { }, }; +static struct clk_regmap s4_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = s4_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), + }, +}; + static struct clk_regmap s4_cts_vdac_sel = { .data = &(struct clk_regmap_mux_data){ .offset = CLKCTRL_VIID_CLK_DIV, @@ -1205,6 +1221,22 @@ static struct clk_regmap s4_cts_encp = { }, }; +static struct clk_regmap s4_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap s4_cts_vdac = { .data = &(struct clk_regmap_gate_data){ .offset = CLKCTRL_VID_CLK_CTRL2, @@ -2735,6 +2767,165 @@ static struct clk_regmap s4_gen_clk = { }, }; +/* CVBS DAC */ +static struct clk_regmap s4_cdac_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div5" }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_cdac_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .shift = 0, + .width = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cdac = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cdac_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div7" }, + { .fw_name = "fclk_div4" } + }, + .num_parents = 3, + }, +}; + +static struct clk_regmap s4_demod_core_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 8 + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* CVBS ADC */ +static struct clk_regmap s4_adc_extclk_in_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "fclk_div7" }, + { .fw_name = "mpll2" }, + { .fw_name = "gp0_pll" }, + { .fw_name = "hifi_pll" } + }, + .num_parents = 8, + }, +}; + +static struct clk_regmap s4_adc_extclk_in_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_adc_extclk_in = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 24 + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct clk_parent_data s4_pclk_parents = { .hw = &s4_sys_clk.hw }; #define S4_PCLK(_name, _reg, _bit, _flags) \ @@ -3028,6 +3219,17 @@ static struct clk_hw *s4_peripherals_hw_clks[] = { [CLKID_HDCP22_SKPCLK_SEL] = &s4_hdcp22_skpclk_sel.hw, [CLKID_HDCP22_SKPCLK_DIV] = &s4_hdcp22_skpclk_div.hw, [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk.hw, + [CLKID_CTS_ENCL_SEL] = &s4_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &s4_cts_encl.hw, + [CLKID_CDAC_SEL] = &s4_cdac_sel.hw, + [CLKID_CDAC_DIV] = &s4_cdac_div.hw, + [CLKID_CDAC] = &s4_cdac.hw, + [CLKID_DEMOD_CORE_SEL] = &s4_demod_core_sel.hw, + [CLKID_DEMOD_CORE_DIV] = &s4_demod_core_div.hw, + [CLKID_DEMOD_CORE] = &s4_demod_core.hw, + [CLKID_ADC_EXTCLK_IN_SEL] = &s4_adc_extclk_in_sel.hw, + [CLKID_ADC_EXTCLK_IN_DIV] = &s4_adc_extclk_in_div.hw, + [CLKID_ADC_EXTCLK_IN] = &s4_adc_extclk_in.hw, }; static const struct meson_clkc_data s4_peripherals_clkc_data = { From 4aca7e92023cac5018b4053bae324450f884c937 Mon Sep 17 00:00:00 2001 From: Chuan Liu Date: Fri, 19 Sep 2025 13:59:01 +0800 Subject: [PATCH 08/38] clk: amlogic: remove potentially unsafe flags from S4 video clocks The video clocks enci, encp, vdac and hdmitx share the same clock source. Adding CLK_SET_RATE_PARENT to the mux may unintentionally change the shared parent clock, which could affect other video clocks. Signed-off-by: Chuan Liu Link: https://lore.kernel.org/r/20250919-add_video_clk-v6-3-fe223161fb3f@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/s4-peripherals.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index aa500ea8ef9c..ba41fcd90588 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -1107,7 +1107,6 @@ static struct clk_regmap s4_cts_enci_sel = { .ops = &clk_regmap_mux_ops, .parent_hws = s4_cts_parents, .num_parents = ARRAY_SIZE(s4_cts_parents), - .flags = CLK_SET_RATE_PARENT, }, }; @@ -1123,7 +1122,6 @@ static struct clk_regmap s4_cts_encp_sel = { .ops = &clk_regmap_mux_ops, .parent_hws = s4_cts_parents, .num_parents = ARRAY_SIZE(s4_cts_parents), - .flags = CLK_SET_RATE_PARENT, }, }; @@ -1154,7 +1152,6 @@ static struct clk_regmap s4_cts_vdac_sel = { .ops = &clk_regmap_mux_ops, .parent_hws = s4_cts_parents, .num_parents = ARRAY_SIZE(s4_cts_parents), - .flags = CLK_SET_RATE_PARENT, }, }; @@ -1185,7 +1182,6 @@ static struct clk_regmap s4_hdmi_tx_sel = { .ops = &clk_regmap_mux_ops, .parent_hws = s4_hdmi_tx_parents, .num_parents = ARRAY_SIZE(s4_hdmi_tx_parents), - .flags = CLK_SET_RATE_PARENT, }, }; From 5f352125f8a0bc906dff8419a2377903012d7f35 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:10 +0000 Subject: [PATCH 09/38] dt-bindings: clock: thead,th1520-clk-ap: Add ID for C910 bus clock Add binding ID for C910 bus clock, which takes CLK_C910 as parent and is essential for C910 cluster's operation. Acked-by: Conor Dooley Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- include/dt-bindings/clock/thead,th1520-clk-ap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/thead,th1520-clk-ap.h b/include/dt-bindings/clock/thead,th1520-clk-ap.h index 09a9aa7b3ab1..68b35cc61204 100644 --- a/include/dt-bindings/clock/thead,th1520-clk-ap.h +++ b/include/dt-bindings/clock/thead,th1520-clk-ap.h @@ -93,6 +93,7 @@ #define CLK_SRAM3 83 #define CLK_PLL_GMAC_100M 84 #define CLK_UART_SCLK 85 +#define CLK_C910_BUS 86 /* VO clocks */ #define CLK_AXI4_VO_ACLK 0 From 892abfbed71e8e0fc5d6ccee1e975904805c6327 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:11 +0000 Subject: [PATCH 10/38] clk: thead: th1520-ap: Poll for PLL lock and wait for stability All PLLs found on TH1520 SoC take 21250ns at maximum to lock, and their lock status is indicated by register PLL_STS (offset 0x80 inside AP clock controller). We should poll the register to ensure the PLL actually locks after enabling it. Furthermore, a 30us delay is added after enabling the PLL, after which the PLL could be considered stable as stated by vendor clock code. Fixes: 56a48c1833aa ("clk: thead: add support for enabling/disabling PLLs") Reviewed-by: Drew Fustini Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 34 +++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 71ad03a998e8..d870f0c665f8 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -8,11 +8,14 @@ #include #include #include +#include #include #include #include #include +#define TH1520_PLL_STS 0x80 + #define TH1520_PLL_POSTDIV2 GENMASK(26, 24) #define TH1520_PLL_POSTDIV1 GENMASK(22, 20) #define TH1520_PLL_FBDIV GENMASK(19, 8) @@ -23,6 +26,13 @@ #define TH1520_PLL_FRAC GENMASK(23, 0) #define TH1520_PLL_FRAC_BITS 24 +/* + * All PLLs in TH1520 take 21250ns at maximum to lock, let's take its double + * for safety. + */ +#define TH1520_PLL_LOCK_TIMEOUT_US 44 +#define TH1520_PLL_STABLE_DELAY_US 30 + struct ccu_internal { u8 shift; u8 width; @@ -64,6 +74,7 @@ struct ccu_div { struct ccu_pll { struct ccu_common common; + u32 lock_sts_mask; }; #define TH_CCU_ARG(_shift, _width) \ @@ -299,9 +310,21 @@ static void ccu_pll_disable(struct clk_hw *hw) static int ccu_pll_enable(struct clk_hw *hw) { struct ccu_pll *pll = hw_to_ccu_pll(hw); + u32 reg; + int ret; - return regmap_clear_bits(pll->common.map, pll->common.cfg1, - TH1520_PLL_VCO_RST); + regmap_clear_bits(pll->common.map, pll->common.cfg1, + TH1520_PLL_VCO_RST); + + ret = regmap_read_poll_timeout_atomic(pll->common.map, TH1520_PLL_STS, + reg, reg & pll->lock_sts_mask, + 5, TH1520_PLL_LOCK_TIMEOUT_US); + if (ret) + return ret; + + udelay(TH1520_PLL_STABLE_DELAY_US); + + return 0; } static int ccu_pll_is_enabled(struct clk_hw *hw) @@ -389,6 +412,7 @@ static struct ccu_pll cpu_pll0_clk = { &clk_pll_ops, CLK_IS_CRITICAL), }, + .lock_sts_mask = BIT(1), }; static struct ccu_pll cpu_pll1_clk = { @@ -401,6 +425,7 @@ static struct ccu_pll cpu_pll1_clk = { &clk_pll_ops, CLK_IS_CRITICAL), }, + .lock_sts_mask = BIT(4), }; static struct ccu_pll gmac_pll_clk = { @@ -413,6 +438,7 @@ static struct ccu_pll gmac_pll_clk = { &clk_pll_ops, CLK_IS_CRITICAL), }, + .lock_sts_mask = BIT(3), }; static const struct clk_hw *gmac_pll_clk_parent[] = { @@ -433,6 +459,7 @@ static struct ccu_pll video_pll_clk = { &clk_pll_ops, CLK_IS_CRITICAL), }, + .lock_sts_mask = BIT(7), }; static const struct clk_hw *video_pll_clk_parent[] = { @@ -453,6 +480,7 @@ static struct ccu_pll dpu0_pll_clk = { &clk_pll_ops, 0), }, + .lock_sts_mask = BIT(8), }; static const struct clk_hw *dpu0_pll_clk_parent[] = { @@ -469,6 +497,7 @@ static struct ccu_pll dpu1_pll_clk = { &clk_pll_ops, 0), }, + .lock_sts_mask = BIT(9), }; static const struct clk_hw *dpu1_pll_clk_parent[] = { @@ -485,6 +514,7 @@ static struct ccu_pll tee_pll_clk = { &clk_pll_ops, CLK_IS_CRITICAL), }, + .lock_sts_mask = BIT(10), }; static const struct clk_parent_data c910_i0_parents[] = { From b436f8a82aaa3bd54cb79b1219d94a99f7351d33 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:12 +0000 Subject: [PATCH 11/38] clk: thead: th1520-ap: Add C910 bus clock This divider takes c910_clk as parent and is essential for the C910 cluster to operate, thus is marked as CLK_IS_CRITICAL. Reviewed-by: Drew Fustini Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index d870f0c665f8..b820d47387bb 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -539,6 +539,20 @@ static struct ccu_mux c910_clk = { .mux = TH_CCU_MUX("c910", c910_parents, 0, 1), }; +static struct ccu_div c910_bus_clk = { + .enable = BIT(7), + .div_en = BIT(11), + .div = TH_CCU_DIV_FLAGS(8, 3, 0), + .common = { + .clkid = CLK_C910_BUS, + .cfg0 = 0x100, + .hw.init = CLK_HW_INIT_HW("c910-bus", + &c910_clk.mux.hw, + &ccu_div_ops, + CLK_IS_CRITICAL), + }, +}; + static const struct clk_parent_data ahb2_cpusys_parents[] = { { .hw = &gmac_pll_clk.common.hw }, { .index = 0 } @@ -1051,6 +1065,7 @@ static struct ccu_common *th1520_pll_clks[] = { }; static struct ccu_common *th1520_div_clks[] = { + &c910_bus_clk.common, &ahb2_cpusys_hclk.common, &apb3_cpusys_pclk.common, &axi4_cpusys2_aclk.common, @@ -1194,7 +1209,7 @@ static const struct th1520_plat_data th1520_ap_platdata = { .th1520_mux_clks = th1520_mux_clks, .th1520_gate_clks = th1520_gate_clks, - .nr_clks = CLK_UART_SCLK + 1, + .nr_clks = CLK_C910_BUS + 1, .nr_pll_clks = ARRAY_SIZE(th1520_pll_clks), .nr_div_clks = ARRAY_SIZE(th1520_div_clks), From 238cc6316a885765fd52a6dc65b9ca4e47647b1e Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:13 +0000 Subject: [PATCH 12/38] clk: thead: th1520-ap: Support setting PLL rates TH1520 ships several PLLs that could operate in either integer or fractional mode. However, the TRM only lists a few configuration whose stability is considered guaranteed. Add a table-lookup rate determination logic to support PLL rate setting, and fill up frequency-configuration tables for AP-subsystem PLLs. Reviewed-by: Drew Fustini Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 142 ++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index b820d47387bb..bf8e80c39a9e 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -22,6 +22,7 @@ #define TH1520_PLL_REFDIV GENMASK(5, 0) #define TH1520_PLL_BYPASS BIT(30) #define TH1520_PLL_VCO_RST BIT(29) +#define TH1520_PLL_DACPD BIT(25) #define TH1520_PLL_DSMPD BIT(24) #define TH1520_PLL_FRAC GENMASK(23, 0) #define TH1520_PLL_FRAC_BITS 24 @@ -72,9 +73,19 @@ struct ccu_div { struct ccu_common common; }; +struct ccu_pll_cfg { + unsigned long freq; + u32 fbdiv; + u32 frac; + u32 postdiv1; + u32 postdiv2; +}; + struct ccu_pll { struct ccu_common common; u32 lock_sts_mask; + int cfgnum; + const struct ccu_pll_cfg *cfgs; }; #define TH_CCU_ARG(_shift, _width) \ @@ -391,17 +402,102 @@ static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw, return rate; } +static const struct ccu_pll_cfg *ccu_pll_lookup_best_cfg(struct ccu_pll *pll, + unsigned long rate) +{ + unsigned long best_delta = ULONG_MAX; + const struct ccu_pll_cfg *best_cfg; + int i; + + for (i = 0; i < pll->cfgnum; i++) { + const struct ccu_pll_cfg *cfg = &pll->cfgs[i]; + unsigned long delta; + + delta = abs_diff(cfg->freq, rate); + if (delta < best_delta) { + best_delta = delta; + best_cfg = cfg; + } + } + + return best_cfg; +} + +static int ccu_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct ccu_pll *pll = hw_to_ccu_pll(hw); + + req->rate = ccu_pll_lookup_best_cfg(pll, req->rate)->freq; + + return 0; +} + +static int ccu_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ccu_pll *pll = hw_to_ccu_pll(hw); + const struct ccu_pll_cfg *cfg; + + cfg = ccu_pll_lookup_best_cfg(pll, rate); + + ccu_pll_disable(hw); + + regmap_write(pll->common.map, pll->common.cfg0, + FIELD_PREP(TH1520_PLL_REFDIV, 1) | + FIELD_PREP(TH1520_PLL_FBDIV, cfg->fbdiv) | + FIELD_PREP(TH1520_PLL_POSTDIV1, cfg->postdiv1) | + FIELD_PREP(TH1520_PLL_POSTDIV2, cfg->postdiv2)); + + regmap_update_bits(pll->common.map, pll->common.cfg1, + TH1520_PLL_DACPD | TH1520_PLL_DSMPD | + TH1520_PLL_FRAC, + cfg->frac ? cfg->frac : + TH1520_PLL_DACPD | TH1520_PLL_DSMPD); + + return ccu_pll_enable(hw); +} + static const struct clk_ops clk_pll_ops = { .disable = ccu_pll_disable, .enable = ccu_pll_enable, .is_enabled = ccu_pll_is_enabled, .recalc_rate = ccu_pll_recalc_rate, + .determine_rate = ccu_pll_determine_rate, + .set_rate = ccu_pll_set_rate, }; static const struct clk_parent_data osc_24m_clk[] = { { .index = 0 } }; +static const struct ccu_pll_cfg cpu_pll_cfgs[] = { + { 125000000, 125, 0, 6, 4 }, + { 200000000, 125, 0, 5, 3 }, + { 300000000, 125, 0, 5, 2 }, + { 400000000, 100, 0, 3, 2 }, + { 500000000, 125, 0, 6, 1 }, + { 600000000, 125, 0, 5, 1 }, + { 702000000, 117, 0, 4, 1 }, + { 800000000, 100, 0, 3, 1 }, + { 900000000, 75, 0, 2, 1 }, + { 1000000000, 125, 0, 3, 1 }, + { 1104000000, 92, 0, 2, 1 }, + { 1200000000, 100, 0, 2, 1 }, + { 1296000000, 108, 0, 2, 1 }, + { 1404000000, 117, 0, 2, 1 }, + { 1500000000, 125, 0, 2, 1 }, + { 1608000000, 67, 0, 1, 1 }, + { 1704000000, 71, 0, 1, 1 }, + { 1800000000, 75, 0, 1, 1 }, + { 1896000000, 79, 0, 1, 1 }, + { 1992000000, 83, 0, 1, 1 }, + { 2112000000, 88, 0, 1, 1 }, + { 2208000000, 92, 0, 1, 1 }, + { 2304000000, 96, 0, 1, 1 }, + { 2400000000, 100, 0, 1, 1 }, +}; + static struct ccu_pll cpu_pll0_clk = { .common = { .clkid = CLK_CPU_PLL0, @@ -413,6 +509,8 @@ static struct ccu_pll cpu_pll0_clk = { CLK_IS_CRITICAL), }, .lock_sts_mask = BIT(1), + .cfgnum = ARRAY_SIZE(cpu_pll_cfgs), + .cfgs = cpu_pll_cfgs, }; static struct ccu_pll cpu_pll1_clk = { @@ -426,6 +524,16 @@ static struct ccu_pll cpu_pll1_clk = { CLK_IS_CRITICAL), }, .lock_sts_mask = BIT(4), + .cfgnum = ARRAY_SIZE(cpu_pll_cfgs), + .cfgs = cpu_pll_cfgs, +}; + +static const struct ccu_pll_cfg gmac_pll_cfg = { + .freq = 1000000000, + .fbdiv = 125, + .frac = 0, + .postdiv1 = 3, + .postdiv2 = 1, }; static struct ccu_pll gmac_pll_clk = { @@ -439,6 +547,8 @@ static struct ccu_pll gmac_pll_clk = { CLK_IS_CRITICAL), }, .lock_sts_mask = BIT(3), + .cfgnum = 1, + .cfgs = &gmac_pll_cfg, }; static const struct clk_hw *gmac_pll_clk_parent[] = { @@ -449,6 +559,14 @@ static const struct clk_parent_data gmac_pll_clk_pd[] = { { .hw = &gmac_pll_clk.common.hw } }; +static const struct ccu_pll_cfg video_pll_cfg = { + .freq = 792000000, + .fbdiv = 99, + .frac = 0, + .postdiv1 = 3, + .postdiv2 = 1, +}; + static struct ccu_pll video_pll_clk = { .common = { .clkid = CLK_VIDEO_PLL, @@ -460,6 +578,8 @@ static struct ccu_pll video_pll_clk = { CLK_IS_CRITICAL), }, .lock_sts_mask = BIT(7), + .cfgnum = 1, + .cfgs = &video_pll_cfg, }; static const struct clk_hw *video_pll_clk_parent[] = { @@ -470,6 +590,14 @@ static const struct clk_parent_data video_pll_clk_pd[] = { { .hw = &video_pll_clk.common.hw } }; +static const struct ccu_pll_cfg dpu_pll_cfg = { + .freq = 1188000000, + .fbdiv = 99, + .frac = 0, + .postdiv1 = 2, + .postdiv2 = 1, +}; + static struct ccu_pll dpu0_pll_clk = { .common = { .clkid = CLK_DPU0_PLL, @@ -481,6 +609,8 @@ static struct ccu_pll dpu0_pll_clk = { 0), }, .lock_sts_mask = BIT(8), + .cfgnum = 1, + .cfgs = &dpu_pll_cfg, }; static const struct clk_hw *dpu0_pll_clk_parent[] = { @@ -498,12 +628,22 @@ static struct ccu_pll dpu1_pll_clk = { 0), }, .lock_sts_mask = BIT(9), + .cfgnum = 1, + .cfgs = &dpu_pll_cfg, }; static const struct clk_hw *dpu1_pll_clk_parent[] = { &dpu1_pll_clk.common.hw }; +static const struct ccu_pll_cfg tee_pll_cfg = { + .freq = 792000000, + .fbdiv = 99, + .frac = 0, + .postdiv1 = 3, + .postdiv2 = 1, +}; + static struct ccu_pll tee_pll_clk = { .common = { .clkid = CLK_TEE_PLL, @@ -515,6 +655,8 @@ static struct ccu_pll tee_pll_clk = { CLK_IS_CRITICAL), }, .lock_sts_mask = BIT(10), + .cfgnum = 1, + .cfgs = &tee_pll_cfg, }; static const struct clk_parent_data c910_i0_parents[] = { From 5dbee3503771a36464e0b39a420475a727911c83 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:14 +0000 Subject: [PATCH 13/38] clk: thead: th1520-ap: Add macro to define multiplexers with flags The new macro, TH_CCU_MUX_FLAGS, extends TH_CCU_MUX macro by adding two parameters to specify clock flags and multiplexer flags. Reviewed-by: Drew Fustini Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index bf8e80c39a9e..79f001a047b2 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -101,17 +101,22 @@ struct ccu_pll { .flags = _flags, \ } -#define TH_CCU_MUX(_name, _parents, _shift, _width) \ +#define TH_CCU_MUX_FLAGS(_name, _parents, _shift, _width, _flags, \ + _mux_flags) \ { \ .mask = GENMASK(_width - 1, 0), \ .shift = _shift, \ + .flags = _mux_flags, \ .hw.init = CLK_HW_INIT_PARENTS_DATA( \ _name, \ _parents, \ &clk_mux_ops, \ - 0), \ + _flags), \ } +#define TH_CCU_MUX(_name, _parents, _shift, _width) \ + TH_CCU_MUX_FLAGS(_name, _parents, _shift, _width, 0, 0) + #define CCU_GATE(_clkid, _struct, _name, _parent, _reg, _bit, _flags) \ struct ccu_gate _struct = { \ .clkid = _clkid, \ From db1cc4902f2f51977e427f796ea8daf49ba93c69 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Wed, 19 Nov 2025 17:17:42 +0530 Subject: [PATCH 14/38] dt-bindings: clock: exynosautov920: add MFD clock definitions Add device tree clock binding definitions for CMU_MFD Signed-off-by: Raghav Sharma Reviewed-by: Alim Akhtar Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20251119114744.1914416-2-raghav.s@samsung.com Signed-off-by: Krzysztof Kozlowski --- .../clock/samsung,exynosautov920-clock.yaml | 19 +++++++++++++++++++ .../clock/samsung,exynosautov920.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml index 5bf905f88a1a..1318720193b3 100644 --- a/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml +++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml @@ -40,6 +40,7 @@ properties: - samsung,exynosautov920-cmu-hsi2 - samsung,exynosautov920-cmu-m2m - samsung,exynosautov920-cmu-mfc + - samsung,exynosautov920-cmu-mfd - samsung,exynosautov920-cmu-misc - samsung,exynosautov920-cmu-peric0 - samsung,exynosautov920-cmu-peric1 @@ -268,6 +269,24 @@ allOf: - const: mfc - const: wfd + - if: + properties: + compatible: + contains: + const: samsung,exynosautov920-cmu-mfd + + then: + properties: + clocks: + items: + - description: External reference clock (38.4 MHz) + - description: CMU_MFD NOC clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: noc + required: - compatible - "#clock-cells" diff --git a/include/dt-bindings/clock/samsung,exynosautov920.h b/include/dt-bindings/clock/samsung,exynosautov920.h index 970d05167fc6..06dec27a8c77 100644 --- a/include/dt-bindings/clock/samsung,exynosautov920.h +++ b/include/dt-bindings/clock/samsung,exynosautov920.h @@ -305,4 +305,8 @@ #define CLK_MOUT_MFC_WFD_USER 2 #define CLK_DOUT_MFC_NOCP 3 +/* CMU_MFD */ +#define CLK_MOUT_MFD_NOC_USER 1 +#define CLK_DOUT_MFD_NOCP 2 + #endif /* _DT_BINDINGS_CLOCK_EXYNOSAUTOV920_H */ From efa45bcc73e1a30705eed28933e341d36a08bb84 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Wed, 19 Nov 2025 17:17:43 +0530 Subject: [PATCH 15/38] clk: samsung: exynosautov920: add clock support Add support for CMU_MFD which provides clocks to MFD block, and register the required compatible and cmu_info for the same. Signed-off-by: Raghav Sharma Reviewed-by: Alim Akhtar Link: https://patch.msgid.link/20251119114744.1914416-3-raghav.s@samsung.com Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynosautov920.c | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/clk/samsung/clk-exynosautov920.c b/drivers/clk/samsung/clk-exynosautov920.c index b90b73c3518f..d0617c7fff3a 100644 --- a/drivers/clk/samsung/clk-exynosautov920.c +++ b/drivers/clk/samsung/clk-exynosautov920.c @@ -29,6 +29,7 @@ #define CLKS_NR_HSI2 (CLK_DOUT_HSI2_ETHERNET_PTP + 1) #define CLKS_NR_M2M (CLK_DOUT_M2M_NOCP + 1) #define CLKS_NR_MFC (CLK_DOUT_MFC_NOCP + 1) +#define CLKS_NR_MFD (CLK_DOUT_MFD_NOCP + 1) /* ---- CMU_TOP ------------------------------------------------------------ */ @@ -1905,6 +1906,42 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = { .clk_name = "noc", }; +/* ---- CMU_MFD --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_MFD (0x19e00000) */ +#define PLL_CON0_MUX_CLKCMU_MFD_NOC_USER 0x600 +#define CLK_CON_DIV_DIV_CLK_MFD_NOCP 0x1800 + +static const unsigned long mfd_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_MFD_NOC_USER, + CLK_CON_DIV_DIV_CLK_MFD_NOCP, +}; + +/* List of parent clocks for Muxes in CMU_MFD */ +PNAME(mout_clkcmu_mfd_noc_user_p) = { "oscclk", "dout_clkcmu_mfd_noc" }; + +static const struct samsung_mux_clock mfd_mux_clks[] __initconst = { + MUX(CLK_MOUT_MFD_NOC_USER, "mout_clkcmu_mfd_noc_user", + mout_clkcmu_mfd_noc_user_p, PLL_CON0_MUX_CLKCMU_MFD_NOC_USER, 4, 1), +}; + +static const struct samsung_div_clock mfd_div_clks[] __initconst = { + DIV(CLK_DOUT_MFD_NOCP, "dout_mfd_nocp", + "mout_clkcmu_mfd_noc_user", CLK_CON_DIV_DIV_CLK_MFD_NOCP, + 0, 3), +}; + +static const struct samsung_cmu_info mfd_cmu_info __initconst = { + .mux_clks = mfd_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mfd_mux_clks), + .div_clks = mfd_div_clks, + .nr_div_clks = ARRAY_SIZE(mfd_div_clks), + .nr_clk_ids = CLKS_NR_MFD, + .clk_regs = mfd_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mfd_clk_regs), + .clk_name = "noc", +}; + static int __init exynosautov920_cmu_probe(struct platform_device *pdev) { const struct samsung_cmu_info *info; @@ -1941,6 +1978,9 @@ static const struct of_device_id exynosautov920_cmu_of_match[] = { }, { .compatible = "samsung,exynosautov920-cmu-mfc", .data = &mfc_cmu_info, + }, { + .compatible = "samsung,exynosautov920-cmu-mfd", + .data = &mfd_cmu_info, }, { } }; From 2e8e9a2492edbbef54de6ab1c5bf1578ffef4c8c Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 22 Dec 2025 10:22:12 +0000 Subject: [PATCH 16/38] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each CMU (with the exception of cmu_top) has a corresponding sysreg bank that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers. The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of bus components and MEMCLK gates the sram clock. Now the clock driver supports automatic clock mode, to fully enable dynamic root clock gating it is required to configure these registers. Update the bindings documentation so that all CMUs (with the exception of gs101-cmu-top) have samsung,sysreg as a required property. Note this is NOT an ABI break, as if the property isn't specified the clock driver will fallback to the current behaviour of not initializing the registers. The system still boots, but bus components won't benefit from dynamic root clock gating and dynamic power will be higher (which has been the case until now anyway). Additionally update the DT example to included the correct CMU size as registers in that region are used for automatic clock mode. Acked-by: Rob Herring (Arm) Reviewed-by: André Draszik Reviewed-by: Rob Herring (Arm) Signed-off-by: Peter Griffin Link: https://patch.msgid.link/20251222-automatic-clocks-v7-1-fec86fa89874@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/clock/google,gs101-clock.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml index 31e106ef913d..09e679c1a9de 100644 --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml @@ -52,6 +52,11 @@ properties: reg: maxItems: 1 + samsung,sysreg: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to system registers interface. + required: - compatible - "#clock-cells" @@ -166,6 +171,18 @@ allOf: - const: bus - const: ip + - if: + properties: + compatible: + contains: + const: google,gs101-cmu-top + then: + properties: + samsung,sysreg: false + else: + required: + - samsung,sysreg + additionalProperties: false examples: @@ -175,7 +192,7 @@ examples: cmu_top: clock-controller@1e080000 { compatible = "google,gs101-cmu-top"; - reg = <0x1e080000 0x8000>; + reg = <0x1e080000 0x10000>; #clock-cells = <1>; clocks = <&ext_24_5m>; clock-names = "oscclk"; From 298fac4f4b96448ce7ef8da525a74fd3dba0035d Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 22 Dec 2025 10:22:14 +0000 Subject: [PATCH 17/38] clk: samsung: Implement automatic clock gating mode for CMUs Update exynos_arm64_init_clocks() so that it enables the automatic clock mode bits in the CMU option register if the auto_clock_gate flag and option_offset fields are set for the CMU. To ensure compatibility with older DTs (that specified an incorrect CMU reg size), detect this and fallback to manual clock gate mode as the auto clock mode feature depends on registers in this area. The CMU option register bits are global and effect every clock component in the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL bit on every gate register is only required if auto_clock_gate is false. Additionally if auto_clock_gate is enabled the dynamic root clock gating and memclk registers will be configured in the corresponding CMUs sysreg bank. These registers are exposed via syscon, so the register samsung_clk_save/restore paths are updated to also take a regmap. As many gates for various Samsung SoCs are already exposed in the Samsung clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses some CMU debug registers to report whether clocks are enabled or disabled when operating in automatic mode. This allows /sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and correctly report the status of each clock in the system. Signed-off-by: Peter Griffin Link: https://patch.msgid.link/20251222-automatic-clocks-v7-3-fec86fa89874@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos-arm64.c | 62 ++++++- drivers/clk/samsung/clk-exynos4.c | 12 +- drivers/clk/samsung/clk-exynos4412-isp.c | 4 +- drivers/clk/samsung/clk-exynos5250.c | 2 +- drivers/clk/samsung/clk-exynos5420.c | 4 +- drivers/clk/samsung/clk-s3c64xx.c | 4 +- drivers/clk/samsung/clk-s5pv210.c | 2 +- drivers/clk/samsung/clk.c | 200 +++++++++++++++++++++-- drivers/clk/samsung/clk.h | 55 ++++++- 9 files changed, 302 insertions(+), 43 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c index bf7de21f329e..11e4d49f2390 100644 --- a/drivers/clk/samsung/clk-exynos-arm64.c +++ b/drivers/clk/samsung/clk-exynos-arm64.c @@ -24,6 +24,16 @@ #define GATE_MANUAL BIT(20) #define GATE_ENABLE_HWACG BIT(28) +/* Option register bits */ +#define OPT_EN_MEM_PWR_GATING BIT(24) +#define OPT_EN_AUTO_GATING BIT(28) +#define OPT_EN_PWR_MANAGEMENT BIT(29) +#define OPT_EN_LAYER2_CTRL BIT(30) +#define OPT_EN_DBG BIT(31) + +#define CMU_OPT_GLOBAL_EN_AUTO_GATING (OPT_EN_DBG | OPT_EN_LAYER2_CTRL | \ + OPT_EN_PWR_MANAGEMENT | OPT_EN_AUTO_GATING | OPT_EN_MEM_PWR_GATING) + /* PLL_CONx_PLL register offsets range */ #define PLL_CON_OFF_START 0x100 #define PLL_CON_OFF_END 0x600 @@ -37,6 +47,8 @@ struct exynos_arm64_cmu_data { unsigned int nr_clk_save; const struct samsung_clk_reg_dump *clk_suspend; unsigned int nr_clk_suspend; + struct samsung_clk_reg_dump *clk_sysreg_save; + unsigned int nr_clk_sysreg; struct clk *clk; struct clk **pclks; @@ -76,19 +88,41 @@ static void __init exynos_arm64_init_clocks(struct device_node *np, const unsigned long *reg_offs = cmu->clk_regs; size_t reg_offs_len = cmu->nr_clk_regs; void __iomem *reg_base; + bool init_auto; size_t i; reg_base = of_iomap(np, 0); if (!reg_base) panic("%s: failed to map registers\n", __func__); + /* ensure compatibility with older DTs */ + if (cmu->auto_clock_gate && samsung_is_auto_capable(np)) + init_auto = true; + else + init_auto = false; + + if (cmu->option_offset && init_auto) { + /* + * Enable the global automatic mode for the entire CMU. + * This overrides the individual HWACG bits in each of the + * individual gate, mux and qch registers. + */ + writel(CMU_OPT_GLOBAL_EN_AUTO_GATING, + reg_base + cmu->option_offset); + } + for (i = 0; i < reg_offs_len; ++i) { void __iomem *reg = reg_base + reg_offs[i]; u32 val; if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) { writel(PLL_CON1_MANUAL, reg); - } else if (is_gate_reg(reg_offs[i])) { + } else if (is_gate_reg(reg_offs[i]) && !init_auto) { + /* + * Setting GATE_MANUAL bit (which is described in TRM as + * reserved!) overrides the global CMU automatic mode + * option. + */ val = readl(reg); val |= GATE_MANUAL; val &= ~GATE_ENABLE_HWACG; @@ -210,8 +244,8 @@ void __init exynos_arm64_register_cmu(struct device *dev, /** * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support * - * @pdev: Platform device object - * @set_manual: If true, set gate clocks to manual mode + * @pdev: Platform device object + * @init_clk_regs: If true, initialize CMU registers * * It's a version of exynos_arm64_register_cmu() with PM support. Should be * called from probe function of platform driver. @@ -219,7 +253,7 @@ void __init exynos_arm64_register_cmu(struct device *dev, * Return: 0 on success, or negative error code on error. */ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, - bool set_manual) + bool init_clk_regs) { const struct samsung_cmu_info *cmu; struct device *dev = &pdev->dev; @@ -249,7 +283,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, dev_err(dev, "%s: could not enable bus clock %s; err = %d\n", __func__, cmu->clk_name, ret); - if (set_manual) + if (init_clk_regs) exynos_arm64_init_clocks(np, cmu); reg_base = devm_platform_ioremap_resource(pdev, 0); @@ -268,8 +302,10 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, pm_runtime_set_active(dev); pm_runtime_enable(dev); - samsung_cmu_register_clocks(data->ctx, cmu); + samsung_cmu_register_clocks(data->ctx, cmu, np); samsung_clk_of_add_provider(dev->of_node, data->ctx); + /* sysreg DT nodes reference a clock in this CMU */ + samsung_en_dyn_root_clk_gating(np, data->ctx, cmu); pm_runtime_put_sync(dev); return 0; @@ -280,14 +316,17 @@ int exynos_arm64_cmu_suspend(struct device *dev) struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); int i; - samsung_clk_save(data->ctx->reg_base, data->clk_save, + samsung_clk_save(data->ctx->reg_base, NULL, data->clk_save, data->nr_clk_save); + samsung_clk_save(NULL, data->ctx->sysreg, data->clk_sysreg_save, + data->nr_clk_sysreg); + for (i = 0; i < data->nr_pclks; i++) clk_prepare_enable(data->pclks[i]); /* For suspend some registers have to be set to certain values */ - samsung_clk_restore(data->ctx->reg_base, data->clk_suspend, + samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_suspend, data->nr_clk_suspend); for (i = 0; i < data->nr_pclks; i++) @@ -308,9 +347,14 @@ int exynos_arm64_cmu_resume(struct device *dev) for (i = 0; i < data->nr_pclks; i++) clk_prepare_enable(data->pclks[i]); - samsung_clk_restore(data->ctx->reg_base, data->clk_save, + samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_save, data->nr_clk_save); + if (data->ctx->sysreg) + samsung_clk_restore(NULL, data->ctx->sysreg, + data->clk_sysreg_save, + data->nr_clk_sysreg); + for (i = 0; i < data->nr_pclks; i++) clk_disable_unprepare(data->pclks[i]); diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index cc5c1644c41c..246bd28bac2d 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1361,12 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4x12_plls)); } - samsung_cmu_register_clocks(ctx, &cmu_info_exynos4); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4, np); if (exynos4_soc == EXYNOS4210) { - samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210, np); } else { - samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12, np); if (soc == EXYNOS4412) samsung_clk_register_cpu(ctx, exynos4412_cpu_clks, ARRAY_SIZE(exynos4412_cpu_clks)); @@ -1378,15 +1378,15 @@ static void __init exynos4_clk_init(struct device_node *np, if (soc == EXYNOS4212 || soc == EXYNOS4412) exynos4x12_core_down_clock(); - samsung_clk_extended_sleep_init(reg_base, + samsung_clk_extended_sleep_init(reg_base, NULL, exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), src_mask_suspend, ARRAY_SIZE(src_mask_suspend)); if (exynos4_soc == EXYNOS4210) - samsung_clk_extended_sleep_init(reg_base, + samsung_clk_extended_sleep_init(reg_base, NULL, exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save), src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210)); else - samsung_clk_sleep_init(reg_base, exynos4x12_clk_save, + samsung_clk_sleep_init(reg_base, NULL, exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save)); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index fa915057e109..772bc18a1e68 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -94,7 +94,7 @@ static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev) { struct samsung_clk_provider *ctx = dev_get_drvdata(dev); - samsung_clk_save(ctx->reg_base, exynos4x12_save_isp, + samsung_clk_save(ctx->reg_base, NULL, exynos4x12_save_isp, ARRAY_SIZE(exynos4x12_clk_isp_save)); return 0; } @@ -103,7 +103,7 @@ static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev) { struct samsung_clk_provider *ctx = dev_get_drvdata(dev); - samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp, + samsung_clk_restore(ctx->reg_base, NULL, exynos4x12_save_isp, ARRAY_SIZE(exynos4x12_clk_isp_save)); return 0; } diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index e90d3a0848cb..f97f30b29be7 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -854,7 +854,7 @@ static void __init exynos5250_clk_init(struct device_node *np) PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO); __raw_writel(tmp, reg_base + PWR_CTRL2); - samsung_clk_sleep_init(reg_base, exynos5250_clk_regs, + samsung_clk_sleep_init(reg_base, NULL, exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs)); exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus), exynos5250_subcmus); diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index a9df4e6db82f..1982e0751cee 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1649,12 +1649,12 @@ static void __init exynos5x_clk_init(struct device_node *np, ARRAY_SIZE(exynos5800_cpu_clks)); } - samsung_clk_extended_sleep_init(reg_base, + samsung_clk_extended_sleep_init(reg_base, NULL, exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs), exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc)); if (soc == EXYNOS5800) { - samsung_clk_sleep_init(reg_base, exynos5800_clk_regs, + samsung_clk_sleep_init(reg_base, NULL, exynos5800_clk_regs, ARRAY_SIZE(exynos5800_clk_regs)); exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus), diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 397a057af5d1..5a2d5a5703ff 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -449,10 +449,10 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, samsung_clk_register_alias(ctx, s3c64xx_clock_aliases, ARRAY_SIZE(s3c64xx_clock_aliases)); - samsung_clk_sleep_init(reg_base, s3c64xx_clk_regs, + samsung_clk_sleep_init(reg_base, NULL, s3c64xx_clk_regs, ARRAY_SIZE(s3c64xx_clk_regs)); if (!is_s3c6400) - samsung_clk_sleep_init(reg_base, s3c6410_clk_regs, + samsung_clk_sleep_init(reg_base, NULL, s3c6410_clk_regs, ARRAY_SIZE(s3c6410_clk_regs)); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c index 9a4217cc1908..4ee4f2b5efbc 100644 --- a/drivers/clk/samsung/clk-s5pv210.c +++ b/drivers/clk/samsung/clk-s5pv210.c @@ -782,7 +782,7 @@ static void __init __s5pv210_clk_init(struct device_node *np, samsung_clk_register_alias(ctx, s5pv210_aliases, ARRAY_SIZE(s5pv210_aliases)); - samsung_clk_sleep_init(reg_base, s5pv210_clk_regs, + samsung_clk_sleep_init(reg_base, NULL, s5pv210_clk_regs, ARRAY_SIZE(s5pv210_clk_regs)); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index c149ca6c2217..06ea5deef4ee 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include "clk.h" @@ -21,19 +23,29 @@ static LIST_HEAD(clock_reg_cache_list); void samsung_clk_save(void __iomem *base, + struct regmap *regmap, struct samsung_clk_reg_dump *rd, unsigned int num_regs) { - for (; num_regs > 0; --num_regs, ++rd) - rd->value = readl(base + rd->offset); + for (; num_regs > 0; --num_regs, ++rd) { + if (base) + rd->value = readl(base + rd->offset); + else if (regmap) + regmap_read(regmap, rd->offset, &rd->value); + } } void samsung_clk_restore(void __iomem *base, + struct regmap *regmap, const struct samsung_clk_reg_dump *rd, unsigned int num_regs) { - for (; num_regs > 0; --num_regs, ++rd) - writel(rd->value, base + rd->offset); + for (; num_regs > 0; --num_regs, ++rd) { + if (base) + writel(rd->value, base + rd->offset); + else if (regmap) + regmap_write(regmap, rd->offset, rd->value); + } } struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( @@ -227,6 +239,103 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx, } } +/* + * Some older DT's have an incorrect CMU resource size which is incompatible + * with the auto clock mode feature. In such cases we switch back to manual + * clock gating mode. + */ +bool samsung_is_auto_capable(struct device_node *np) +{ + struct resource res; + resource_size_t size; + + if (of_address_to_resource(np, 0, &res)) + return false; + + size = resource_size(&res); + if (size != 0x10000) { + pr_warn("%pOF: incorrect res size for automatic clocks\n", np); + return false; + } + return true; +} + +#define ACG_MSK GENMASK(6, 4) +#define CLK_IDLE GENMASK(5, 4) +static int samsung_auto_clk_gate_is_en(struct clk_hw *hw) +{ + u32 reg; + struct clk_gate *gate = to_clk_gate(hw); + + reg = readl(gate->reg); + return ((reg & ACG_MSK) == CLK_IDLE) ? 0 : 1; +} + +/* enable and disable are nops in automatic clock mode */ +static int samsung_auto_clk_gate_en(struct clk_hw *hw) +{ + return 0; +} + +static void samsung_auto_clk_gate_dis(struct clk_hw *hw) +{ +} + +static const struct clk_ops samsung_auto_clk_gate_ops = { + .enable = samsung_auto_clk_gate_en, + .disable = samsung_auto_clk_gate_dis, + .is_enabled = samsung_auto_clk_gate_is_en, +}; + +struct clk_hw *samsung_register_auto_gate(struct device *dev, + struct device_node *np, const char *name, + const char *parent_name, const struct clk_hw *parent_hw, + const struct clk_parent_data *parent_data, + unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk_hw *hw; + struct clk_init_data init = {}; + int ret = -EINVAL; + + /* allocate the gate */ + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &samsung_auto_clk_gate_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.parent_hws = parent_hw ? &parent_hw : NULL; + init.parent_data = parent_data; + if (parent_name || parent_hw || parent_data) + init.num_parents = 1; + else + init.num_parents = 0; + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate_flags; + gate->lock = lock; + gate->hw.init = &init; + + hw = &gate->hw; + if (dev || !np) + ret = clk_hw_register(dev, hw); + else if (np) + ret = of_clk_hw_register(np, hw); + if (ret) { + kfree(gate); + hw = ERR_PTR(ret); + } + + return hw; +} + /* register a list of gate clocks */ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, const struct samsung_gate_clock *list, @@ -234,14 +343,24 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, { struct clk_hw *clk_hw; unsigned int idx; + void __iomem *reg_offs; for (idx = 0; idx < nr_clk; idx++, list++) { - clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name, - list->flags, ctx->reg_base + list->offset, + reg_offs = ctx->reg_base + list->offset; + + if (ctx->auto_clock_gate && ctx->gate_dbg_offset) + clk_hw = samsung_register_auto_gate(ctx->dev, NULL, + list->name, list->parent_name, NULL, NULL, + list->flags, reg_offs + ctx->gate_dbg_offset, list->bit_idx, list->gate_flags, &ctx->lock); + else + clk_hw = clk_hw_register_gate(ctx->dev, list->name, + list->parent_name, list->flags, + ctx->reg_base + list->offset, list->bit_idx, + list->gate_flags, &ctx->lock); if (IS_ERR(clk_hw)) { - pr_err("%s: failed to register clock %s\n", __func__, - list->name); + pr_err("%s: failed to register clock %s: %ld\n", __func__, + list->name, PTR_ERR(clk_hw)); continue; } @@ -276,10 +395,11 @@ static int samsung_clk_suspend(void *data) struct samsung_clock_reg_cache *reg_cache; list_for_each_entry(reg_cache, &clock_reg_cache_list, node) { - samsung_clk_save(reg_cache->reg_base, reg_cache->rdump, - reg_cache->rd_num); - samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend, - reg_cache->rsuspend_num); + samsung_clk_save(reg_cache->reg_base, reg_cache->sysreg, + reg_cache->rdump, reg_cache->rd_num); + samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg, + reg_cache->rsuspend, + reg_cache->rsuspend_num); } return 0; } @@ -289,8 +409,8 @@ static void samsung_clk_resume(void *data) struct samsung_clock_reg_cache *reg_cache; list_for_each_entry(reg_cache, &clock_reg_cache_list, node) - samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump, - reg_cache->rd_num); + samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg, + reg_cache->rdump, reg_cache->rd_num); } static const struct syscore_ops samsung_clk_syscore_ops = { @@ -303,6 +423,7 @@ static struct syscore samsung_clk_syscore = { }; void samsung_clk_extended_sleep_init(void __iomem *reg_base, + struct regmap *sysreg, const unsigned long *rdump, unsigned long nr_rdump, const struct samsung_clk_reg_dump *rsuspend, @@ -323,6 +444,7 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base, register_syscore(&samsung_clk_syscore); reg_cache->reg_base = reg_base; + reg_cache->sysreg = sysreg; reg_cache->rd_num = nr_rdump; reg_cache->rsuspend = rsuspend; reg_cache->rsuspend_num = nr_rsuspend; @@ -334,10 +456,20 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base, * samsung_cmu_register_clocks() - Register all clocks provided in CMU object * @ctx: Clock provider object * @cmu: CMU object with clocks to register + * @np: CMU device tree node */ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, - const struct samsung_cmu_info *cmu) + const struct samsung_cmu_info *cmu, + struct device_node *np) { + if (samsung_is_auto_capable(np) && cmu->auto_clock_gate) + ctx->auto_clock_gate = cmu->auto_clock_gate; + + ctx->gate_dbg_offset = cmu->gate_dbg_offset; + ctx->option_offset = cmu->option_offset; + ctx->drcg_offset = cmu->drcg_offset; + ctx->memclk_offset = cmu->memclk_offset; + if (cmu->pll_clks) samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks); if (cmu->mux_clks) @@ -357,6 +489,37 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks); } +/* Each bit enable/disables DRCG of a bus component */ +#define DRCG_EN_MSK GENMASK(31, 0) +#define MEMCLK_EN BIT(0) + +/* Enable Dynamic Root Clock Gating (DRCG) of bus components */ +void samsung_en_dyn_root_clk_gating(struct device_node *np, + struct samsung_clk_provider *ctx, + const struct samsung_cmu_info *cmu) +{ + if (!ctx->auto_clock_gate) + return; + + ctx->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg"); + if (IS_ERR(ctx->sysreg)) { + pr_warn("%pOF: Unable to get CMU sysreg\n", np); + ctx->sysreg = NULL; + } else { + /* Enable DRCG for all bus components */ + regmap_write(ctx->sysreg, ctx->drcg_offset, DRCG_EN_MSK); + /* Enable memclk gate (not present on all sysreg) */ + if (ctx->memclk_offset) + regmap_write_bits(ctx->sysreg, ctx->memclk_offset, + MEMCLK_EN, 0x0); + + samsung_clk_extended_sleep_init(NULL, ctx->sysreg, + cmu->sysreg_clk_regs, + cmu->nr_sysreg_clk_regs, + NULL, 0); + } +} + /* * Common function which registers plls, muxes, dividers and gates * for each CMU. It also add CMU register list to register cache. @@ -375,14 +538,17 @@ struct samsung_clk_provider * __init samsung_cmu_register_one( } ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids); - samsung_cmu_register_clocks(ctx, cmu); + samsung_cmu_register_clocks(ctx, cmu, np); if (cmu->clk_regs) - samsung_clk_extended_sleep_init(reg_base, + samsung_clk_extended_sleep_init(reg_base, NULL, cmu->clk_regs, cmu->nr_clk_regs, cmu->suspend_regs, cmu->nr_suspend_regs); samsung_clk_of_add_provider(np, ctx); + /* sysreg DT nodes reference a clock in this CMU */ + samsung_en_dyn_root_clk_gating(np, ctx, cmu); + return ctx; } diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 18660c1ac6f0..a56aa3be54d8 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -12,6 +12,7 @@ #include #include +#include #include "clk-pll.h" #include "clk-cpu.h" @@ -19,13 +20,25 @@ * struct samsung_clk_provider - information about clock provider * @reg_base: virtual address for the register base * @dev: clock provider device needed for runtime PM + * @sysreg: syscon regmap for clock-provider sysreg controller * @lock: maintains exclusion between callbacks for a given clock-provider + * @auto_clock_gate: enable auto clk mode for all clocks in clock-provider + * @gate_dbg_offset: gate debug reg offset. Used for all gates in auto clk mode + * @option_offset: option reg offset. Enables auto mode for clock-provider + * @drcg_offset: dynamic root clk gate enable register offset in sysreg + * @memclk_offset: memclk enable register offset in sysreg * @clk_data: holds clock related data like clk_hw* and number of clocks */ struct samsung_clk_provider { void __iomem *reg_base; struct device *dev; + struct regmap *sysreg; spinlock_t lock; + bool auto_clock_gate; + u32 gate_dbg_offset; + u32 option_offset; + u32 drcg_offset; + u32 memclk_offset; /* clk_data must be the last entry due to variable length 'hws' array */ struct clk_hw_onecell_data clk_data; }; @@ -310,6 +323,7 @@ struct samsung_cpu_clock { struct samsung_clock_reg_cache { struct list_head node; void __iomem *reg_base; + struct regmap *sysreg; struct samsung_clk_reg_dump *rdump; unsigned int rd_num; const struct samsung_clk_reg_dump *rsuspend; @@ -338,7 +352,14 @@ struct samsung_clock_reg_cache { * @suspend_regs: list of clock registers to set before suspend * @nr_suspend_regs: count of clock registers in @suspend_regs * @clk_name: name of the parent clock needed for CMU register access + * @sysreg_clk_regs: list of sysreg clock registers + * @nr_sysreg_clk_regs: count of clock registers in @sysreg_clk_regs * @manual_plls: Enable manual control for PLL clocks + * @auto_clock_gate: enable auto clock mode for all components in CMU + * @gate_dbg_offset: gate debug reg offset. Used by all gates in auto clk mode + * @option_offset: option reg offset. Enables auto clk mode for entire CMU + * @drcg_offset: dynamic root clk gate enable register offset in sysreg + * @memclk_offset: memclk enable register offset in sysreg */ struct samsung_cmu_info { const struct samsung_pll_clock *pll_clks; @@ -364,8 +385,16 @@ struct samsung_cmu_info { unsigned int nr_suspend_regs; const char *clk_name; + const unsigned long *sysreg_clk_regs; + unsigned int nr_sysreg_clk_regs; + /* ARM64 Exynos CMUs */ bool manual_plls; + bool auto_clock_gate; + u32 gate_dbg_offset; + u32 option_offset; + u32 drcg_offset; + u32 memclk_offset; }; struct samsung_clk_provider *samsung_clk_init(struct device *dev, @@ -408,35 +437,55 @@ void samsung_clk_register_cpu(struct samsung_clk_provider *ctx, const struct samsung_cpu_clock *list, unsigned int nr_clk); void samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, - const struct samsung_cmu_info *cmu); + const struct samsung_cmu_info *cmu, + struct device_node *np); struct samsung_clk_provider *samsung_cmu_register_one( struct device_node *, const struct samsung_cmu_info *); #ifdef CONFIG_PM_SLEEP void samsung_clk_extended_sleep_init(void __iomem *reg_base, + struct regmap *sysreg, const unsigned long *rdump, unsigned long nr_rdump, const struct samsung_clk_reg_dump *rsuspend, unsigned long nr_rsuspend); #else static inline void samsung_clk_extended_sleep_init(void __iomem *reg_base, + struct regmap *sysreg, const unsigned long *rdump, unsigned long nr_rdump, const struct samsung_clk_reg_dump *rsuspend, unsigned long nr_rsuspend) {} #endif -#define samsung_clk_sleep_init(reg_base, rdump, nr_rdump) \ - samsung_clk_extended_sleep_init(reg_base, rdump, nr_rdump, NULL, 0) +#define samsung_clk_sleep_init(reg_base, sysreg, rdump, nr_rdump) \ + samsung_clk_extended_sleep_init(reg_base, sysreg, rdump, nr_rdump, \ + NULL, 0) void samsung_clk_save(void __iomem *base, + struct regmap *regmap, struct samsung_clk_reg_dump *rd, unsigned int num_regs); void samsung_clk_restore(void __iomem *base, + struct regmap *regmap, const struct samsung_clk_reg_dump *rd, unsigned int num_regs); struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( const unsigned long *rdump, unsigned long nr_rdump); +void samsung_en_dyn_root_clk_gating(struct device_node *np, + struct samsung_clk_provider *ctx, + const struct samsung_cmu_info *cmu); + +struct clk_hw *samsung_register_auto_gate(struct device *dev, + struct device_node *np, const char *name, + const char *parent_name, const struct clk_hw *parent_hw, + const struct clk_parent_data *parent_data, + unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + +bool samsung_is_auto_capable(struct device_node *np); + #endif /* __SAMSUNG_CLK_H */ From eaf9206bf3d68f792ecd5e6f488eab1fb5afe900 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 22 Dec 2025 10:22:15 +0000 Subject: [PATCH 18/38] clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU Enable auto clock mode, and define the additional fields which are used when this mode is enabled. /sys/kernel/debug/clk/clk_summary now reports approximately 308 running clocks and 298 disabled clocks. Prior to this commit 586 clocks were running and 17 disabled. Signed-off-by: Peter Griffin Link: https://patch.msgid.link/20251222-automatic-clocks-v7-4-fec86fa89874@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-gs101.c | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c index 70b26db9b95a..8551289b46eb 100644 --- a/drivers/clk/samsung/clk-gs101.c +++ b/drivers/clk/samsung/clk-gs101.c @@ -26,6 +26,10 @@ #define CLKS_NR_PERIC0 (CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK + 1) #define CLKS_NR_PERIC1 (CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK + 1) +#define GS101_GATE_DBG_OFFSET 0x4000 +#define GS101_DRCG_EN_OFFSET 0x104 +#define GS101_MEMCLK_OFFSET 0x108 + /* ---- CMU_TOP ------------------------------------------------------------- */ /* Register Offset definitions for CMU_TOP (0x1e080000) */ @@ -1433,6 +1437,9 @@ static const struct samsung_cmu_info top_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_TOP, .clk_regs = cmu_top_clk_regs, .nr_clk_regs = ARRAY_SIZE(cmu_top_clk_regs), + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = CMU_CMU_TOP_CONTROLLER_OPTION, }; static void __init gs101_cmu_top_init(struct device_node *np) @@ -1900,6 +1907,11 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = { CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, 21, CLK_IS_CRITICAL, 0), }; +static const unsigned long dcrg_memclk_sysreg[] __initconst = { + GS101_DRCG_EN_OFFSET, + GS101_MEMCLK_OFFSET, +}; + static const struct samsung_cmu_info apm_cmu_info __initconst = { .mux_clks = apm_mux_clks, .nr_mux_clks = ARRAY_SIZE(apm_mux_clks), @@ -1912,6 +1924,12 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_APM, .clk_regs = apm_clk_regs, .nr_clk_regs = ARRAY_SIZE(apm_clk_regs), + .sysreg_clk_regs = dcrg_memclk_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg), + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .drcg_offset = GS101_DRCG_EN_OFFSET, + .memclk_offset = GS101_MEMCLK_OFFSET, }; /* ---- CMU_HSI0 ------------------------------------------------------------ */ @@ -2375,7 +2393,14 @@ static const struct samsung_cmu_info hsi0_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_HSI0, .clk_regs = hsi0_clk_regs, .nr_clk_regs = ARRAY_SIZE(hsi0_clk_regs), + .sysreg_clk_regs = dcrg_memclk_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg), .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = HSI0_CMU_HSI0_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, + .memclk_offset = GS101_MEMCLK_OFFSET, }; /* ---- CMU_HSI2 ------------------------------------------------------------ */ @@ -2863,7 +2888,14 @@ static const struct samsung_cmu_info hsi2_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_HSI2, .clk_regs = cmu_hsi2_clk_regs, .nr_clk_regs = ARRAY_SIZE(cmu_hsi2_clk_regs), + .sysreg_clk_regs = dcrg_memclk_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg), .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = HSI2_CMU_HSI2_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, + .memclk_offset = GS101_MEMCLK_OFFSET, }; /* ---- CMU_MISC ------------------------------------------------------------ */ @@ -3423,7 +3455,14 @@ static const struct samsung_cmu_info misc_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_MISC, .clk_regs = misc_clk_regs, .nr_clk_regs = ARRAY_SIZE(misc_clk_regs), + .sysreg_clk_regs = dcrg_memclk_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg), .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = MISC_CMU_MISC_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, + .memclk_offset = GS101_MEMCLK_OFFSET, }; static void __init gs101_cmu_misc_init(struct device_node *np) @@ -4010,6 +4049,10 @@ static const struct samsung_gate_clock peric0_gate_clks[] __initconst = { 21, 0, 0), }; +static const unsigned long dcrg_sysreg[] __initconst = { + GS101_DRCG_EN_OFFSET, +}; + static const struct samsung_cmu_info peric0_cmu_info __initconst = { .mux_clks = peric0_mux_clks, .nr_mux_clks = ARRAY_SIZE(peric0_mux_clks), @@ -4020,7 +4063,13 @@ static const struct samsung_cmu_info peric0_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_PERIC0, .clk_regs = peric0_clk_regs, .nr_clk_regs = ARRAY_SIZE(peric0_clk_regs), + .sysreg_clk_regs = dcrg_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_sysreg), .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = PERIC0_CMU_PERIC0_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, }; /* ---- CMU_PERIC1 ---------------------------------------------------------- */ @@ -4368,7 +4417,13 @@ static const struct samsung_cmu_info peric1_cmu_info __initconst = { .nr_clk_ids = CLKS_NR_PERIC1, .clk_regs = peric1_clk_regs, .nr_clk_regs = ARRAY_SIZE(peric1_clk_regs), + .sysreg_clk_regs = dcrg_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_sysreg), .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = PERIC1_CMU_PERIC1_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, }; /* ---- platform_driver ----------------------------------------------------- */ From 5b1a43950fd3162af0ce52b13c14a2d29b179d4f Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 5 Jan 2026 21:47:08 +0100 Subject: [PATCH 19/38] clk: meson: gxbb: Limit the HDMI PLL OD to /4 on GXL/GXM SoCs GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for GXL/GXM the OD has moved to HHI_HDMI_PLL_CNTL3. At first glance the rest of the OD setup seems identical. However, looking at the downstream kernel sources as well as testing shows that GXL only supports three OD values: - register value 0 means: divide by 1 - register value 1 means: divide by 2 - register value 2 means: divide by 4 Using register value 3 (which on GXBB means: divide by 8) still divides by 4 as verified using meson-clk-measure. Downstream sources are also only using OD register values 0, 1 and 2 for GXL (while for GXBB the downstream kernel sources are also using value 3). Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag to make the kernel's view of this register match with how the hardware actually works. Fixes: 69d92293274b ("clk: meson: add the gxl hdmi pll") Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20260105204710.447779-2-martin.blumenstingl@googlemail.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 5a229c4ffae1..ec9a3414875a 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -349,12 +349,23 @@ static struct clk_regmap gxbb_hdmi_pll = { }, }; +/* + * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. + * A divider value of 3 should map to /8 but instead map /4 so ignore it. + */ +static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { /* sentinel */ } +}; + static struct clk_regmap gxl_hdmi_pll_od = { .data = &(struct clk_regmap_div_data){ .offset = HHI_HDMI_PLL_CNTL + 8, .shift = 21, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = gxl_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od", @@ -372,7 +383,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { .offset = HHI_HDMI_PLL_CNTL + 8, .shift = 23, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = gxl_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od2", @@ -390,7 +401,7 @@ static struct clk_regmap gxl_hdmi_pll = { .offset = HHI_HDMI_PLL_CNTL + 8, .shift = 19, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = gxl_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", From 7aa6c24697ef5db1402dd38743914493cd5b356d Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 5 Jan 2026 21:47:09 +0100 Subject: [PATCH 20/38] clk: meson: g12a: Limit the HDMI PLL OD to /4 GXBB has the HDMI PLL OD in the HHI_HDMI_PLL_CNTL2 register while for G12A/G12B/SM1 the OD has moved to HHI_HDMI_PLL_CNTL0. At first glance the rest of the OD setup seems identical. However, looking at the downstream kernel sources as well as testing shows that G12A/G12B/SM1 only supports three OD values: - register value 0 means: divide by 1 - register value 1 means: divide by 2 - register value 2 means: divide by 4 Downstream sources are also only using OD register values 0, 1 and 2 for G12A/G12B/SM1 (while for GXBB the downstream kernel sources are also using value 3 which means: divide by 8). Add clk_div_table and have it replace the CLK_DIVIDER_POWER_OF_TWO flag to make the kernel's view of this register match with how the hardware actually works. Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20260105204710.447779-3-martin.blumenstingl@googlemail.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/g12a.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 185b6348251d..d0d4c7b6dc82 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -777,12 +777,23 @@ static struct clk_regmap g12a_hdmi_pll_dco = { }, }; +/* + * G12/SM1 hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. + * A divider value of 3 should map to /8 but instead map /4 so ignore it. + */ +static const struct clk_div_table g12a_hdmi_pll_od_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { /* sentinel */ } +}; + static struct clk_regmap g12a_hdmi_pll_od = { .data = &(struct clk_regmap_div_data){ .offset = HHI_HDMI_PLL_CNTL0, .shift = 16, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = g12a_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od", @@ -800,7 +811,7 @@ static struct clk_regmap g12a_hdmi_pll_od2 = { .offset = HHI_HDMI_PLL_CNTL0, .shift = 18, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = g12a_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_od2", @@ -818,7 +829,7 @@ static struct clk_regmap g12a_hdmi_pll = { .offset = HHI_HDMI_PLL_CNTL0, .shift = 20, .width = 2, - .flags = CLK_DIVIDER_POWER_OF_TWO, + .table = g12a_hdmi_pll_od_div_table, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", From 2fe1ef40b58c2256f4682594f48bfbd584501ec5 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 5 Jan 2026 21:47:10 +0100 Subject: [PATCH 21/38] clk: meson: gxbb: use the existing HHI_HDMI_PLL_CNTL3 macro There's no need to calculate HHI_HDMI_PLL_CNTL + 8 when we have a HHI_HDMI_PLL_CNTL3 macro that has the correct offset already. No functional changes, this makes it easier to compare the driver with the datasheets. Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20260105204710.447779-4-martin.blumenstingl@googlemail.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ec9a3414875a..f9131d014ef4 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -362,7 +362,7 @@ static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { static struct clk_regmap gxl_hdmi_pll_od = { .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL + 8, + .offset = HHI_HDMI_PLL_CNTL3, .shift = 21, .width = 2, .table = gxl_hdmi_pll_od_div_table, @@ -380,7 +380,7 @@ static struct clk_regmap gxl_hdmi_pll_od = { static struct clk_regmap gxl_hdmi_pll_od2 = { .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL + 8, + .offset = HHI_HDMI_PLL_CNTL3, .shift = 23, .width = 2, .table = gxl_hdmi_pll_od_div_table, @@ -398,7 +398,7 @@ static struct clk_regmap gxl_hdmi_pll_od2 = { static struct clk_regmap gxl_hdmi_pll = { .data = &(struct clk_regmap_div_data){ - .offset = HHI_HDMI_PLL_CNTL + 8, + .offset = HHI_HDMI_PLL_CNTL3, .shift = 19, .width = 2, .table = gxl_hdmi_pll_od_div_table, From baf4fc7c03bd0f68c768cfe27829674bd060c6b4 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 20 Nov 2025 13:14:15 +0000 Subject: [PATCH 22/38] clk: thead: th1520-ap: Support CPU frequency scaling On TH1520 SoC, c910_clk feeds the CPU cluster. It could be glitchlessly reparented to one of the two PLLs: either to cpu_pll0 indirectly through c910_i0_clk, or to cpu_pll1 directly. To achieve glitchless rate change, customized clock operations are implemented for c910_clk: on rate change, the PLL not currently in use is configured to the requested rate first, then c910_clk reparents to it. Additionally, c910_bus_clk, which in turn takes c910_clk as parent, has a frequency limit of 750MHz. A clock notifier is registered on c910_clk to adjust c910_bus_clk on c910_clk rate change. Reviewed-by: Drew Fustini Signed-off-by: Yao Zi Signed-off-by: Drew Fustini --- drivers/clk/thead/clk-th1520-ap.c | 148 +++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 79f001a047b2..3a6847f1c950 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -7,9 +7,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -34,6 +36,9 @@ #define TH1520_PLL_LOCK_TIMEOUT_US 44 #define TH1520_PLL_STABLE_DELAY_US 30 +/* c910_bus_clk must be kept below 750MHz for stability */ +#define TH1520_C910_BUS_MAX_RATE (750 * 1000 * 1000) + struct ccu_internal { u8 shift; u8 width; @@ -472,6 +477,72 @@ static const struct clk_ops clk_pll_ops = { .set_rate = ccu_pll_set_rate, }; +/* + * c910_clk could be reparented glitchlessly for DVFS. There are two parents, + * - c910_i0_clk, derived from cpu_pll0_clk or osc_24m. + * - cpu_pll1_clk, which provides the exact same set of rates as cpu_pll0_clk. + * + * During rate setting, always forward the request to the unused parent, and + * then switch c910_clk to it to avoid glitch. + */ +static u8 c910_clk_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int c910_clk_set_parent(struct clk_hw *hw, u8 index) +{ + return clk_mux_ops.set_parent(hw, index); +} + +static unsigned long c910_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate; +} + +static int c910_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + u8 alt_parent_index = !c910_clk_get_parent(hw); + struct clk_hw *alt_parent; + + alt_parent = clk_hw_get_parent_by_index(hw, alt_parent_index); + + req->rate = clk_hw_round_rate(alt_parent, req->rate); + req->best_parent_hw = alt_parent; + req->best_parent_rate = req->rate; + + return 0; +} + +static int c910_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return -EOPNOTSUPP; +} + +static int c910_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + struct clk_hw *parent = clk_hw_get_parent_by_index(hw, index); + + clk_set_rate(parent->clk, parent_rate); + + c910_clk_set_parent(hw, index); + + return 0; +} + +static const struct clk_ops c910_clk_ops = { + .get_parent = c910_clk_get_parent, + .set_parent = c910_clk_set_parent, + .recalc_rate = c910_clk_recalc_rate, + .determine_rate = c910_clk_determine_rate, + .set_rate = c910_clk_set_rate, + .set_rate_and_parent = c910_clk_set_rate_and_parent, +}; + static const struct clk_parent_data osc_24m_clk[] = { { .index = 0 } }; @@ -672,7 +743,8 @@ static const struct clk_parent_data c910_i0_parents[] = { static struct ccu_mux c910_i0_clk = { .clkid = CLK_C910_I0, .reg = 0x100, - .mux = TH_CCU_MUX("c910-i0", c910_i0_parents, 1, 1), + .mux = TH_CCU_MUX_FLAGS("c910-i0", c910_i0_parents, 1, 1, + CLK_SET_RATE_PARENT, CLK_MUX_ROUND_CLOSEST), }; static const struct clk_parent_data c910_parents[] = { @@ -683,7 +755,14 @@ static const struct clk_parent_data c910_parents[] = { static struct ccu_mux c910_clk = { .clkid = CLK_C910, .reg = 0x100, - .mux = TH_CCU_MUX("c910", c910_parents, 0, 1), + .mux = { + .mask = BIT(0), + .shift = 0, + .hw.init = CLK_HW_INIT_PARENTS_DATA("c910", + c910_parents, + &c910_clk_ops, + CLK_SET_RATE_PARENT), + }, }; static struct ccu_div c910_bus_clk = { @@ -1372,11 +1451,69 @@ static const struct th1520_plat_data th1520_vo_platdata = { .nr_gate_clks = ARRAY_SIZE(th1520_vo_gate_clks), }; +/* + * Maintain clock rate of c910_bus_clk below TH1520_C910_BUS_MAX_RATE (750MHz) + * when its parent, c910_clk, changes the rate. + * + * Additionally, TRM is unclear about c910_bus_clk behavior when the divisor is + * set below 2, thus we should ensure the new divisor stays in (2, MAXDIVISOR). + */ +static unsigned long c910_bus_clk_divisor(struct ccu_div *cd, + unsigned long parent_rate) +{ + return clamp(DIV_ROUND_UP(parent_rate, TH1520_C910_BUS_MAX_RATE), + 2U, 1U << cd->div.width); +} + +static int c910_clk_notifier_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct clk_notifier_data *cnd = data; + unsigned long new_divisor, ref_rate; + + if (action != PRE_RATE_CHANGE && action != POST_RATE_CHANGE) + return NOTIFY_DONE; + + new_divisor = c910_bus_clk_divisor(&c910_bus_clk, cnd->new_rate); + + if (cnd->new_rate > cnd->old_rate) { + /* + * Scaling up. Adjust c910_bus_clk divisor + * - before c910_clk rate change to ensure the constraints + * aren't broken after scaling to higher rates, + * - after c910_clk rate change to keep c910_bus_clk as high as + * possible + */ + ref_rate = action == PRE_RATE_CHANGE ? + cnd->old_rate : cnd->new_rate; + clk_set_rate(c910_bus_clk.common.hw.clk, + ref_rate / new_divisor); + } else if (cnd->new_rate < cnd->old_rate && + action == POST_RATE_CHANGE) { + /* + * Scaling down. Adjust c910_bus_clk divisor only after + * c910_clk rate change to keep c910_bus_clk as high as + * possible, Scaling down never breaks the constraints. + */ + clk_set_rate(c910_bus_clk.common.hw.clk, + cnd->new_rate / new_divisor); + } else { + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block c910_clk_notifier = { + .notifier_call = c910_clk_notifier_cb, +}; + static int th1520_clk_probe(struct platform_device *pdev) { const struct th1520_plat_data *plat_data; struct device *dev = &pdev->dev; struct clk_hw_onecell_data *priv; + struct clk *notifier_clk; struct regmap *map; void __iomem *base; @@ -1463,6 +1600,13 @@ static int th1520_clk_probe(struct platform_device *pdev) ret = devm_clk_hw_register(dev, &emmc_sdio_ref_clk.hw); if (ret) return ret; + + notifier_clk = devm_clk_hw_get_clk(dev, &c910_clk.mux.hw, + "dvfs"); + ret = devm_clk_notifier_register(dev, notifier_clk, + &c910_clk_notifier); + if (ret) + return ret; } ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv); From aafaa4d875fb8ff525c514e69eb0440c69425c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Fri, 9 Jan 2026 17:27:23 +0000 Subject: [PATCH 23/38] clk: samsung: avoid warning message on legacy Exynos (auto clock gating) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently print a warning message that the IO memory size is not compatible with automatic clock gating for many Exynos-based boards, including legacy ones, even if not requested to enable automatic clock gating in the first place. Change the test in question to avoid that warning. Fixes: 298fac4f4b96 ("clk: samsung: Implement automatic clock gating mode for CMUs") Reported-by: Marek Szyprowski Closes: https://lore.kernel.org/all/8b2c412d-3e1e-4be0-a9d5-ef67f6f0d409@samsung.com/ Suggested-by: Marek Szyprowski Signed-off-by: André Draszik Reviewed-by: Peter Griffin Link: https://patch.msgid.link/20260109-clk-samsung-autoclk-updates-v1-1-2394dcf242a9@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 06ea5deef4ee..417ec1786b5e 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -462,7 +462,7 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, const struct samsung_cmu_info *cmu, struct device_node *np) { - if (samsung_is_auto_capable(np) && cmu->auto_clock_gate) + if (cmu->auto_clock_gate && samsung_is_auto_capable(np)) ctx->auto_clock_gate = cmu->auto_clock_gate; ctx->gate_dbg_offset = cmu->gate_dbg_offset; From c9d24fe079027f143992a4a1c0be74c4f4455f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Fri, 9 Jan 2026 17:27:24 +0000 Subject: [PATCH 24/38] clk: samsung: fix sysreg save/restore when PM is enabled for CMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, sysreg registers of a CMU that has PM and automatic clock gating enabled are not saved / restored during runtime PM (RPM) or s2idle. During normal suspend, they are accessed too late, after the CMU (and potentially power domain) have been shut down, causing an SError. The reason is that these registers are registered to be saved/restored via a syscore suspend handler which doesn't run during RPM or s2idle. During normal suspend, this handler runs after the CMU has been shut down. This registration happens as part of samsung_clk_extended_sleep_init() via samsung_en_dyn_root_clk_gating(). When PM is enabled for a CMU, registers must be saved/restored via exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() respectively instead. These use their own data structures and are unrelated to anything that samsung_clk_extended_sleep_init() does. Calling it unconditionally from samsung_en_dyn_root_clk_gating() therefore isn't useful. Update the code to prepare sysreg save / restore in a similar way to how it handles other clock registers in the PM case already. exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() already handle sysreg save/restore, just the setup was incorrect. Fixes: 298fac4f4b96 ("clk: samsung: Implement automatic clock gating mode for CMUs") Signed-off-by: André Draszik Reviewed-by: Peter Griffin Link: https://patch.msgid.link/20260109-clk-samsung-autoclk-updates-v1-2-2394dcf242a9@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-exynos-arm64.c | 32 +++++++++++++++++++++----- drivers/clk/samsung/clk.c | 19 ++++++++++----- drivers/clk/samsung/clk.h | 3 ++- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c index 11e4d49f2390..35d4de233cc1 100644 --- a/drivers/clk/samsung/clk-exynos-arm64.c +++ b/drivers/clk/samsung/clk-exynos-arm64.c @@ -174,7 +174,7 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev, const struct samsung_cmu_info *cmu) { struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); - int i; + int i, ret; data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs, cmu->nr_clk_regs); @@ -182,8 +182,22 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev, return -ENOMEM; data->nr_clk_save = cmu->nr_clk_regs; + + if (cmu->nr_sysreg_clk_regs) { + data->clk_sysreg_save = + samsung_clk_alloc_reg_dump(cmu->sysreg_clk_regs, + cmu->nr_sysreg_clk_regs); + if (!data->clk_sysreg_save) { + ret = -ENOMEM; + goto free_clk_save; + } + + data->nr_clk_sysreg = cmu->nr_sysreg_clk_regs; + } + data->clk_suspend = cmu->suspend_regs; data->nr_clk_suspend = cmu->nr_suspend_regs; + data->nr_pclks = of_clk_get_parent_count(dev->of_node); if (!data->nr_pclks) return 0; @@ -191,23 +205,29 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev, data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks, GFP_KERNEL); if (!data->pclks) { - kfree(data->clk_save); - return -ENOMEM; + ret = -ENOMEM; + goto free_sysreg_save; } for (i = 0; i < data->nr_pclks; i++) { struct clk *clk = of_clk_get(dev->of_node, i); if (IS_ERR(clk)) { - kfree(data->clk_save); while (--i >= 0) clk_put(data->pclks[i]); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto free_sysreg_save; } data->pclks[i] = clk; } return 0; + +free_sysreg_save: + kfree(data->clk_sysreg_save); +free_clk_save: + kfree(data->clk_save); + return ret; } /** @@ -305,7 +325,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, samsung_cmu_register_clocks(data->ctx, cmu, np); samsung_clk_of_add_provider(dev->of_node, data->ctx); /* sysreg DT nodes reference a clock in this CMU */ - samsung_en_dyn_root_clk_gating(np, data->ctx, cmu); + samsung_en_dyn_root_clk_gating(np, data->ctx, cmu, true); pm_runtime_put_sync(dev); return 0; diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 417ec1786b5e..9f68f079fd55 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -496,7 +496,8 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, /* Enable Dynamic Root Clock Gating (DRCG) of bus components */ void samsung_en_dyn_root_clk_gating(struct device_node *np, struct samsung_clk_provider *ctx, - const struct samsung_cmu_info *cmu) + const struct samsung_cmu_info *cmu, + bool cmu_has_pm) { if (!ctx->auto_clock_gate) return; @@ -513,10 +514,16 @@ void samsung_en_dyn_root_clk_gating(struct device_node *np, regmap_write_bits(ctx->sysreg, ctx->memclk_offset, MEMCLK_EN, 0x0); - samsung_clk_extended_sleep_init(NULL, ctx->sysreg, - cmu->sysreg_clk_regs, - cmu->nr_sysreg_clk_regs, - NULL, 0); + if (!cmu_has_pm) + /* + * When a CMU has PM support, clocks are saved/restored + * via its PM handlers, so only register them with the + * syscore suspend / resume paths if PM is not in use. + */ + samsung_clk_extended_sleep_init(NULL, ctx->sysreg, + cmu->sysreg_clk_regs, + cmu->nr_sysreg_clk_regs, + NULL, 0); } } @@ -548,7 +555,7 @@ struct samsung_clk_provider * __init samsung_cmu_register_one( samsung_clk_of_add_provider(np, ctx); /* sysreg DT nodes reference a clock in this CMU */ - samsung_en_dyn_root_clk_gating(np, ctx, cmu); + samsung_en_dyn_root_clk_gating(np, ctx, cmu, false); return ctx; } diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index a56aa3be54d8..b1192ca03db5 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -476,7 +476,8 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( void samsung_en_dyn_root_clk_gating(struct device_node *np, struct samsung_clk_provider *ctx, - const struct samsung_cmu_info *cmu); + const struct samsung_cmu_info *cmu, + bool cmu_has_pm); struct clk_hw *samsung_register_auto_gate(struct device *dev, struct device_node *np, const char *name, From 3a2741fa31385348c5b501bdcbab6f6d7b4628ac Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 13 Jan 2026 10:58:58 +0000 Subject: [PATCH 25/38] dt-bindings: clock: google,gs101-clock: fix alphanumeric ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure children of cmu_top have alphanumeric ordering. Top is special as it feeds all the other children CMUs. This ordering then matches the clk-gs101.c file. Reviewed-by: André Draszik Signed-off-by: Peter Griffin Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260113-dpu-clocks-v3-1-cb85424f2c72@linaro.org Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/clock/google,gs101-clock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml index 31e106ef913d..82639863b1a4 100644 --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml @@ -29,9 +29,9 @@ properties: enum: - google,gs101-cmu-top - google,gs101-cmu-apm - - google,gs101-cmu-misc - google,gs101-cmu-hsi0 - google,gs101-cmu-hsi2 + - google,gs101-cmu-misc - google,gs101-cmu-peric0 - google,gs101-cmu-peric1 From 52300cd894b3167d6206e266e341a089e87124b9 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 13 Jan 2026 10:58:59 +0000 Subject: [PATCH 26/38] dt-bindings: clock: google,gs101-clock: Add DPU clock management unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add dt schema documentation and clock IDs for the Display Process Unit (DPU) clock management unit (CMU). This CMU feeds IPs such as image scaler, enhancer and compressor. Signed-off-by: Peter Griffin Reviewed-by: Rob Herring (Arm) Reviewed-by: André Draszik Link: https://patch.msgid.link/20260113-dpu-clocks-v3-2-cb85424f2c72@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/clock/google,gs101-clock.yaml | 19 ++++++++++ include/dt-bindings/clock/google,gs101.h | 36 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml index 82639863b1a4..6193c87511fa 100644 --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml @@ -29,6 +29,7 @@ properties: enum: - google,gs101-cmu-top - google,gs101-cmu-apm + - google,gs101-cmu-dpu - google,gs101-cmu-hsi0 - google,gs101-cmu-hsi2 - google,gs101-cmu-misc @@ -77,6 +78,24 @@ allOf: items: - const: oscclk + - if: + properties: + compatible: + contains: + const: google,gs101-cmu-dpu + + then: + properties: + clocks: + items: + - description: External reference clock (24.576 MHz) + - description: DPU bus clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - if: properties: compatible: diff --git a/include/dt-bindings/clock/google,gs101.h b/include/dt-bindings/clock/google,gs101.h index 442f9e9037dc..7a14dcb9f17b 100644 --- a/include/dt-bindings/clock/google,gs101.h +++ b/include/dt-bindings/clock/google,gs101.h @@ -313,6 +313,42 @@ #define CLK_APM_PLL_DIV4_APM 70 #define CLK_APM_PLL_DIV16_APM 71 +/* CMU_DPU */ +#define CLK_MOUT_DPU_BUS_USER 1 +#define CLK_DOUT_DPU_BUSP 2 +#define CLK_GOUT_DPU_PCLK 3 +#define CLK_GOUT_DPU_CLK_DPU_OSCCLK_CLK 4 +#define CLK_GOUT_DPU_AD_APB_DPU_DMA_PCLKM 5 +#define CLK_GOUT_DPU_DPUF_ACLK_DMA 6 +#define CLK_GOUT_DPU_DPUF_ACLK_DPP 7 +#define CLK_GOUT_DPU_D_TZPC_DPU_PCLK 8 +#define CLK_GOUT_DPU_GPC_DPU_PCLK 9 +#define CLK_GOUT_DPU_LHM_AXI_P_DPU_I_CLK 10 +#define CLK_GOUT_DPU_LHS_AXI_D0_DPU_I_CLK 11 +#define CLK_GOUT_DPU_LHS_AXI_D1_DPU_I_CLK 12 +#define CLK_GOUT_DPU_LHS_AXI_D2_DPU_I_CLK 13 +#define CLK_GOUT_DPU_PPMU_DPUD0_ACLK 14 +#define CLK_GOUT_DPU_PPMU_DPUD0_PCLK 15 +#define CLK_GOUT_DPU_PPMU_DPUD1_ACLK 16 +#define CLK_GOUT_DPU_PPMU_DPUD1_PCLK 17 +#define CLK_GOUT_DPU_PPMU_DPUD2_ACLK 18 +#define CLK_GOUT_DPU_PPMU_DPUD2_PCLK 19 +#define CLK_GOUT_DPU_CLK_DPU_BUSD_CLK 20 +#define CLK_GOUT_DPU_CLK_DPU_BUSP_CLK 21 +#define CLK_GOUT_DPU_SSMT_DPU0_ACLK 22 +#define CLK_GOUT_DPU_SSMT_DPU0_PCLK 23 +#define CLK_GOUT_DPU_SSMT_DPU1_ACLK 24 +#define CLK_GOUT_DPU_SSMT_DPU1_PCLK 25 +#define CLK_GOUT_DPU_SSMT_DPU2_ACLK 26 +#define CLK_GOUT_DPU_SSMT_DPU2_PCLK 27 +#define CLK_GOUT_DPU_SYSMMU_DPUD0_CLK_S1 28 +#define CLK_GOUT_DPU_SYSMMU_DPUD0_CLK_S2 29 +#define CLK_GOUT_DPU_SYSMMU_DPUD1_CLK_S1 30 +#define CLK_GOUT_DPU_SYSMMU_DPUD1_CLK_S2 31 +#define CLK_GOUT_DPU_SYSMMU_DPUD2_CLK_S1 32 +#define CLK_GOUT_DPU_SYSMMU_DPUD2_CLK_S2 33 +#define CLK_GOUT_DPU_SYSREG_DPU_PCLK 34 + /* CMU_HSI0 */ #define CLK_FOUT_USB_PLL 1 #define CLK_MOUT_PLL_USB 2 From 1d8fae6617b6ebcaf3ef3040ee84cdde25d5d10f Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 13 Jan 2026 10:59:00 +0000 Subject: [PATCH 27/38] dt-bindings: samsung: exynos-sysreg: add gs101 dpu compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add dedicated compatibles for gs101 dpu sysreg controllers to the documentation. Reviewed-by: André Draszik Signed-off-by: Peter Griffin Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260113-dpu-clocks-v3-3-cb85424f2c72@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 5e1e155510b3..9c63dbcd4d77 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -15,6 +15,7 @@ properties: - items: - enum: - google,gs101-apm-sysreg + - google,gs101-dpu-sysreg - google,gs101-hsi0-sysreg - google,gs101-hsi2-sysreg - google,gs101-misc-sysreg @@ -92,6 +93,7 @@ allOf: compatible: contains: enum: + - google,gs101-dpu-sysreg - google,gs101-hsi0-sysreg - google,gs101-hsi2-sysreg - google,gs101-misc-sysreg From 4b18a3ef2230e38439c9c3a0e3fa4a2b5edcc5cd Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 13 Jan 2026 10:59:01 +0000 Subject: [PATCH 28/38] clk: samsung: gs101: add support for Display Process Unit (DPU) clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmu_dpu is the clock management unit used for the Display Process Unit block. It generates clocks for image scaler, compressor etc. Add support for the muxes, dividers and gates in cmu_dpu. Signed-off-by: Peter Griffin Reviewed-by: André Draszik Link: https://patch.msgid.link/20260113-dpu-clocks-v3-4-cb85424f2c72@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-gs101.c | 283 ++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c index 8551289b46eb..44a8ecd332fd 100644 --- a/drivers/clk/samsung/clk-gs101.c +++ b/drivers/clk/samsung/clk-gs101.c @@ -20,6 +20,7 @@ /* NOTE: Must be equal to the last clock ID increased by one */ #define CLKS_NR_TOP (CLK_GOUT_CMU_TPU_UART + 1) #define CLKS_NR_APM (CLK_APM_PLL_DIV16_APM + 1) +#define CLKS_NR_DPU (CLK_GOUT_DPU_SYSREG_DPU_PCLK + 1) #define CLKS_NR_HSI0 (CLK_GOUT_HSI0_XIU_P_HSI0_ACLK + 1) #define CLKS_NR_HSI2 (CLK_GOUT_HSI2_XIU_P_HSI2_ACLK + 1) #define CLKS_NR_MISC (CLK_GOUT_MISC_XIU_D_MISC_ACLK + 1) @@ -1932,6 +1933,285 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = { .memclk_offset = GS101_MEMCLK_OFFSET, }; +/* ---- CMU_DPU ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_DPU (0x1c000000) */ +#define PLL_CON0_MUX_CLKCMU_DPU_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_DPU_BUS_USER 0x0604 +#define DPU_CMU_DPU_CONTROLLER_OPTION 0x0800 +#define CLKOUT_CON_BLK_DPU_CMU_DPU_CLKOUT0 0x0810 +#define CLK_CON_DIV_DIV_CLK_DPU_BUSP 0x1800 +#define CLK_CON_GAT_CLK_BLK_DPU_UID_DPU_CMU_DPU_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BLK_DPU_UID_RSTNSYNC_CLK_DPU_OSCCLK_IPCLKPORT_CLK 0x2004 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_AD_APB_DPU_DMA_IPCLKPORT_PCLKM 0x2008 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DMA 0x200c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DPP 0x2010 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_D_TZPC_DPU_IPCLKPORT_PCLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_GPC_DPU_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_LHM_AXI_P_DPU_IPCLKPORT_I_CLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D0_DPU_IPCLKPORT_I_CLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D1_DPU_IPCLKPORT_I_CLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D2_DPU_IPCLKPORT_I_CLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_ACLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_PCLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_ACLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_PCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_ACLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_PCLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSD_IPCLKPORT_CLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSP_IPCLKPORT_CLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_ACLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_ACLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_PCLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_ACLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_PCLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S1 0x2064 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S2 0x2068 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S1 0x206c +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S2 0x2070 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S1 0x2074 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S2 0x2078 +#define CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSREG_DPU_IPCLKPORT_PCLK 0x207c +#define PCH_CON_LHM_AXI_P_DPU_PCH 0x3000 +#define PCH_CON_LHS_AXI_D0_DPU_PCH 0x3004 +#define PCH_CON_LHS_AXI_D1_DPU_PCH 0x3008 +#define PCH_CON_LHS_AXI_D2_DPU_PCH 0x300c +#define QCH_CON_DPUF_QCH_DPU_DMA 0x3010 +#define QCH_CON_DPUF_QCH_DPU_DPP 0x3014 +#define QCH_CON_DPU_CMU_DPU_QCH 0x301c +#define QCH_CON_D_TZPC_DPU_QCH 0x3020 +#define QCH_CON_GPC_DPU_QCH 0x3024 +#define QCH_CON_LHM_AXI_P_DPU_QCH 0x3028 +#define QCH_CON_LHS_AXI_D0_DPU_QCH 0x302c +#define QCH_CON_LHS_AXI_D1_DPU_QCH 0x3030 +#define QCH_CON_LHS_AXI_D2_DPU_QCH 0x3034 +#define QCH_CON_PPMU_DPUD0_QCH 0x3038 +#define QCH_CON_PPMU_DPUD1_QCH 0x303c +#define QCH_CON_PPMU_DPUD2_QCH 0x3040 +#define QCH_CON_SSMT_DPU0_QCH 0x3044 +#define QCH_CON_SSMT_DPU1_QCH 0x3048 +#define QCH_CON_SSMT_DPU2_QCH 0x304c +#define QCH_CON_SYSMMU_DPUD0_QCH_S1 0x3050 +#define QCH_CON_SYSMMU_DPUD0_QCH_S2 0x3054 +#define QCH_CON_SYSMMU_DPUD1_QCH_S1 0x3058 +#define QCH_CON_SYSMMU_DPUD1_QCH_S2 0x305c +#define QCH_CON_SYSMMU_DPUD2_QCH_S1 0x3060 +#define QCH_CON_SYSMMU_DPUD2_QCH_S2 0x3064 +#define QCH_CON_SYSREG_DPU_QCH 0x3068 +#define QUEUE_CTRL_REG_BLK_DPU_CMU_DPU 0x3c00 + +static const unsigned long dpu_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_DPU_BUS_USER, + PLL_CON1_MUX_CLKCMU_DPU_BUS_USER, + DPU_CMU_DPU_CONTROLLER_OPTION, + CLKOUT_CON_BLK_DPU_CMU_DPU_CLKOUT0, + CLK_CON_DIV_DIV_CLK_DPU_BUSP, + CLK_CON_GAT_CLK_BLK_DPU_UID_DPU_CMU_DPU_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_DPU_UID_RSTNSYNC_CLK_DPU_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_AD_APB_DPU_DMA_IPCLKPORT_PCLKM, + CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DMA, + CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DPP, + CLK_CON_GAT_GOUT_BLK_DPU_UID_D_TZPC_DPU_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_GPC_DPU_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHM_AXI_P_DPU_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D0_DPU_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D1_DPU_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D2_DPU_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSD_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S1, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S2, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S1, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S2, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S1, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S2, + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSREG_DPU_IPCLKPORT_PCLK, + PCH_CON_LHM_AXI_P_DPU_PCH, + PCH_CON_LHS_AXI_D0_DPU_PCH, + PCH_CON_LHS_AXI_D1_DPU_PCH, + PCH_CON_LHS_AXI_D2_DPU_PCH, + QCH_CON_DPUF_QCH_DPU_DMA, + QCH_CON_DPUF_QCH_DPU_DPP, + QCH_CON_DPU_CMU_DPU_QCH, + QCH_CON_D_TZPC_DPU_QCH, + QCH_CON_GPC_DPU_QCH, + QCH_CON_LHM_AXI_P_DPU_QCH, + QCH_CON_LHS_AXI_D0_DPU_QCH, + QCH_CON_LHS_AXI_D1_DPU_QCH, + QCH_CON_LHS_AXI_D2_DPU_QCH, + QCH_CON_PPMU_DPUD0_QCH, + QCH_CON_PPMU_DPUD1_QCH, + QCH_CON_PPMU_DPUD2_QCH, + QCH_CON_SSMT_DPU0_QCH, + QCH_CON_SSMT_DPU1_QCH, + QCH_CON_SSMT_DPU2_QCH, + QCH_CON_SYSMMU_DPUD0_QCH_S1, + QCH_CON_SYSMMU_DPUD0_QCH_S2, + QCH_CON_SYSMMU_DPUD1_QCH_S1, + QCH_CON_SYSMMU_DPUD1_QCH_S2, + QCH_CON_SYSMMU_DPUD2_QCH_S1, + QCH_CON_SYSMMU_DPUD2_QCH_S2, + QCH_CON_SYSREG_DPU_QCH, + QUEUE_CTRL_REG_BLK_DPU_CMU_DPU, +}; + +/* List of parent clocks for Muxes in CMU_DPU */ +PNAME(mout_dpu_bus_user_p) = { "oscclk", "dout_cmu_dpu_bus" }; + +static const struct samsung_mux_clock dpu_mux_clks[] __initconst = { + MUX(CLK_MOUT_DPU_BUS_USER, "mout_dpu_bus_user", + mout_dpu_bus_user_p, PLL_CON0_MUX_CLKCMU_DPU_BUS_USER, 4, 1), +}; + +static const struct samsung_div_clock dpu_div_clks[] __initconst = { + DIV(CLK_DOUT_DPU_BUSP, "dout_dpu_busp", "mout_dpu_bus_user", + CLK_CON_DIV_DIV_CLK_DPU_BUSP, 0, 3), +}; + +static const struct samsung_gate_clock dpu_gate_clks[] __initconst = { + GATE(CLK_GOUT_DPU_PCLK, "gout_dpu_dpu_pclk", + "dout_dpu_busp", + CLK_CON_GAT_CLK_BLK_DPU_UID_DPU_CMU_DPU_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_CLK_DPU_OSCCLK_CLK, "gout_dpu_clk_dpu_oscclk_clk", + "oscclk", + CLK_CON_GAT_CLK_BLK_DPU_UID_RSTNSYNC_CLK_DPU_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_AD_APB_DPU_DMA_PCLKM, "gout_dpu_ad_apb_dpu_dma_pclkm", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_AD_APB_DPU_DMA_IPCLKPORT_PCLKM, + 21, 0, 0), + GATE(CLK_GOUT_DPU_DPUF_ACLK_DMA, "gout_dpu_dpuf_aclk_dma", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DMA, 21, 0, 0), + GATE(CLK_GOUT_DPU_DPUF_ACLK_DPP, "gout_dpu_dpuf_aclk_dpp", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_DPUF_IPCLKPORT_ACLK_DPP, 21, 0, 0), + GATE(CLK_GOUT_DPU_D_TZPC_DPU_PCLK, "gout_dpu_d_tzpc_dpu_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_D_TZPC_DPU_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_GPC_DPU_PCLK, "gout_dpu_gpc_dpu_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_GPC_DPU_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_LHM_AXI_P_DPU_I_CLK, "gout_dpu_lhm_axi_p_dpu_i_clk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHM_AXI_P_DPU_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_LHS_AXI_D0_DPU_I_CLK, "gout_dpu_lhs_axi_d0_dpu_i_clk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D0_DPU_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_LHS_AXI_D1_DPU_I_CLK, "gout_dpu_lhs_axi_d1_dpu_i_clk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D1_DPU_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_LHS_AXI_D2_DPU_I_CLK, "gout_dpu_lhs_axi_d2_dpu_i_clk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_LHS_AXI_D2_DPU_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD0_ACLK, "gout_dpu_ppmu_dpud0_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD0_PCLK, "gout_dpu_ppmu_dpud0_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD0_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD1_ACLK, "gout_dpu_ppmu_dpud1_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD1_PCLK, "gout_dpu_ppmu_dpud1_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD1_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD2_ACLK, "gout_dpu_ppmu_dpud2_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_DPUD2_PCLK, "gout_dpu_ppmu_dpud2_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_PPMU_DPUD2_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_CLK_DPU_BUSD_CLK, "gout_dpu_clk_dpu_busd_clk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSD_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_CLK_DPU_BUSP_CLK, "gout_dpu_clk_dpu_busp_clk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_RSTNSYNC_CLK_DPU_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU0_ACLK, "gout_dpu_ssmt_dpu0_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU0_PCLK, "gout_dpu_ssmt_dpu0_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU0_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU1_ACLK, "gout_dpu_ssmt_dpu1_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU1_PCLK, "gout_dpu_ssmt_dpu1_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU1_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU2_ACLK, "gout_dpu_ssmt_dpu2_aclk", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SSMT_DPU2_PCLK, "gout_dpu_ssmt_dpu2_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SSMT_DPU2_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD0_CLK_S1, "gout_dpu_sysmmu_dpud0_clk_s1", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S1, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD0_CLK_S2, "gout_dpu_sysmmu_dpud0_clk_s2", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD0_IPCLKPORT_CLK_S2, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD1_CLK_S1, "gout_dpu_sysmmu_dpud1_clk_s1", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S1, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD1_CLK_S2, "gout_dpu_sysmmu_dpud1_clk_s2", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD1_IPCLKPORT_CLK_S2, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD2_CLK_S1, "gout_dpu_sysmmu_dpud2_clk_s1", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S1, + 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSMMU_DPUD2_CLK_S2, "gout_dpu_sysmmu_dpud2_clk_s2", + "mout_dpu_bus_user", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSMMU_DPUD2_IPCLKPORT_CLK_S2, 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSREG_DPU_PCLK, "gout_dpu_sysreg_dpu_pclk", + "dout_dpu_busp", + CLK_CON_GAT_GOUT_BLK_DPU_UID_SYSREG_DPU_IPCLKPORT_PCLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info dpu_cmu_info __initconst = { + .mux_clks = dpu_mux_clks, + .nr_mux_clks = ARRAY_SIZE(dpu_mux_clks), + .div_clks = dpu_div_clks, + .nr_div_clks = ARRAY_SIZE(dpu_div_clks), + .gate_clks = dpu_gate_clks, + .nr_gate_clks = ARRAY_SIZE(dpu_gate_clks), + .nr_clk_ids = CLKS_NR_DPU, + .clk_regs = dpu_clk_regs, + .nr_clk_regs = ARRAY_SIZE(dpu_clk_regs), + .sysreg_clk_regs = dcrg_memclk_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg), + .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = GS101_GATE_DBG_OFFSET, + .option_offset = DPU_CMU_DPU_CONTROLLER_OPTION, + .drcg_offset = GS101_DRCG_EN_OFFSET, +}; + /* ---- CMU_HSI0 ------------------------------------------------------------ */ /* Register Offset definitions for CMU_HSI0 (0x11000000) */ @@ -4443,6 +4723,9 @@ static const struct of_device_id gs101_cmu_of_match[] = { { .compatible = "google,gs101-cmu-apm", .data = &apm_cmu_info, + }, { + .compatible = "google,gs101-cmu-dpu", + .data = &dpu_cmu_info, }, { .compatible = "google,gs101-cmu-hsi0", .data = &hsi0_cmu_info, From 871afb43e41ad4e8246438de495a939cd0f8113c Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Tue, 23 Dec 2025 12:05:17 +0100 Subject: [PATCH 29/38] clk: mediatek: Drop __initconst from gates Since commit 8ceff24a754a ("clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct") the mtk_gate structs are no longer just used for initialization/registration, but also at runtime. So drop __initconst annotations. Fixes: 8ceff24a754a ("clk: mediatek: clk-gate: Refactor mtk_clk_register_gate to use mtk_gate struct") Signed-off-by: Sjoerd Simons Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Laura Nao Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7981-eth.c | 6 +++--- drivers/clk/mediatek/clk-mt8516.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c index 906aec9ddff5..0655ebb6c561 100644 --- a/drivers/clk/mediatek/clk-mt7981-eth.c +++ b/drivers/clk/mediatek/clk-mt7981-eth.c @@ -31,7 +31,7 @@ static const struct mtk_gate_regs sgmii0_cg_regs = { .ops = &mtk_clk_gate_ops_no_setclr_inv, \ } -static const struct mtk_gate sgmii0_clks[] __initconst = { +static const struct mtk_gate sgmii0_clks[] = { GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2), GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3), GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4), @@ -53,7 +53,7 @@ static const struct mtk_gate_regs sgmii1_cg_regs = { .ops = &mtk_clk_gate_ops_no_setclr_inv, \ } -static const struct mtk_gate sgmii1_clks[] __initconst = { +static const struct mtk_gate sgmii1_clks[] = { GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2), GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3), GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4), @@ -75,7 +75,7 @@ static const struct mtk_gate_regs eth_cg_regs = { .ops = &mtk_clk_gate_ops_no_setclr_inv, \ } -static const struct mtk_gate eth_clks[] __initconst = { +static const struct mtk_gate eth_clks[] = { GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6), GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7), GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8), diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c index 21eb052b0a53..342a59019fea 100644 --- a/drivers/clk/mediatek/clk-mt8516.c +++ b/drivers/clk/mediatek/clk-mt8516.c @@ -544,7 +544,7 @@ static const struct mtk_gate_regs top5_cg_regs = { #define GATE_TOP5(_id, _name, _parent, _shift) \ GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -static const struct mtk_gate top_clks[] __initconst = { +static const struct mtk_gate top_clks[] = { /* TOP1 */ GATE_TOP1(CLK_TOP_THEM, "them", "ahb_infra_sel", 1), GATE_TOP1(CLK_TOP_APDMA, "apdma", "ahb_infra_sel", 2), From a2ed1aed687a21738a6c8bd4043149c443298e88 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 13 Jan 2026 12:00:08 +0100 Subject: [PATCH 30/38] dt-bindings: clock: mediatek,mt7622-pciesys: Remove syscon compatible The PCIESYS register space contains a pure clock controller, which has no system controller register, so this definitely doesn't need any "syscon" compatible. As a side note, luckily no devicetree ever added the syscon string to PCIESYS clock controller node compatibles, so this also resolves a dtbs_check warning for mt7622. Signed-off-by: AngeloGioacchino Del Regno Acked-by: Rob Herring (Arm) Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd --- .../bindings/clock/mediatek,mt7622-pciesys.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7622-pciesys.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7622-pciesys.yaml index 9c3913f9092c..c77111d10f90 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,mt7622-pciesys.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7622-pciesys.yaml @@ -14,11 +14,9 @@ maintainers: properties: compatible: - oneOf: - - items: - - const: mediatek,mt7622-pciesys - - const: syscon - - const: mediatek,mt7629-pciesys + enum: + - mediatek,mt7622-pciesys + - mediatek,mt7629-pciesys reg: maxItems: 1 @@ -40,7 +38,7 @@ additionalProperties: false examples: - | clock-controller@1a100800 { - compatible = "mediatek,mt7622-pciesys", "syscon"; + compatible = "mediatek,mt7622-pciesys"; reg = <0x1a100800 0x1000>; #clock-cells = <1>; #reset-cells = <1>; From 669917676e93fca5ea3c66fc9539830312bec58e Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 15 Dec 2025 11:23:58 +0100 Subject: [PATCH 31/38] clk: Respect CLK_OPS_PARENT_ENABLE during recalc When CLK_OPS_PARENT_ENABLE was introduced, it guarded various clock operations, such as setting the rate or switching parents. However, another operation that can and often does touch actual hardware state is recalc_rate, which may also be affected by such a dependency. Add parent enables/disables where the recalc_rate op is called directly. Fixes: fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)") Fixes: a4b3518d146f ("clk: core: support clocks which requires parents enable (part 1)") Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Nicolas Frattaroli Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 85d2f2481acf..1b0f9d567f48 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1921,7 +1921,14 @@ static unsigned long clk_recalc(struct clk_core *core, unsigned long rate = parent_rate; if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) { + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); + rate = core->ops->recalc_rate(core->hw, parent_rate); + + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); + clk_pm_runtime_put(core); } return rate; @@ -4031,6 +4038,9 @@ static int __clk_core_init(struct clk_core *core) */ clk_core_update_duty_cycle_nolock(core); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); + /* * Set clk's rate. The preferred method is to use .recalc_rate. For * simple clocks and lazy developers the default fallback is to use the @@ -4046,6 +4056,9 @@ static int __clk_core_init(struct clk_core *core) rate = 0; core->rate = core->req_rate = rate; + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); + /* * Enable CLK_IS_CRITICAL clocks so newly added critical clocks * don't get accidentally disabled when walking the orphan tree and From c9ced38af56fe6411118c6bc6522eab80849326d Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 15 Dec 2025 11:23:59 +0100 Subject: [PATCH 32/38] clk: mediatek: Refactor pll registration to pass device As it stands, mtk_clk_register_plls takes a struct device_node pointer as its first argument. This is a tragic happenstance, as it's trivial to get the device_node from a struct device, but the opposite not so much. The struct device is a much more useful thing to have passed down. Refactor mtk_clk_register_plls to take a struct device pointer instead of a struct device_node pointer, and fix up all users of this function. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chen-Yu Tsai Signed-off-by: Nicolas Frattaroli Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2701.c | 2 +- drivers/clk/mediatek/clk-mt2712-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt6735-apmixedsys.c | 4 ++-- drivers/clk/mediatek/clk-mt6765.c | 2 +- drivers/clk/mediatek/clk-mt6779.c | 2 +- drivers/clk/mediatek/clk-mt6797.c | 2 +- drivers/clk/mediatek/clk-mt7622-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt7629.c | 2 +- drivers/clk/mediatek/clk-mt7981-apmixed.c | 2 +- drivers/clk/mediatek/clk-mt7986-apmixed.c | 2 +- drivers/clk/mediatek/clk-mt7988-apmixed.c | 2 +- drivers/clk/mediatek/clk-mt8135-apmixedsys.c | 3 ++- drivers/clk/mediatek/clk-mt8167-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8183-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8188-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8195-apusys_pll.c | 3 ++- drivers/clk/mediatek/clk-mt8196-apmixedsys.c | 3 ++- drivers/clk/mediatek/clk-mt8196-mcu.c | 2 +- drivers/clk/mediatek/clk-mt8196-mfg.c | 2 +- drivers/clk/mediatek/clk-mt8196-vlpckgen.c | 2 +- drivers/clk/mediatek/clk-mt8365-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8516-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-pll.c | 7 ++++--- drivers/clk/mediatek/clk-pll.h | 10 ++++------ 24 files changed, 34 insertions(+), 32 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 1e88ad8b93f4..d9f40fda73d1 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -978,7 +978,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls), + mtk_clk_register_plls(&pdev->dev, apmixed_plls, ARRAY_SIZE(apmixed_plls), clk_data); mtk_clk_register_factors(apmixed_fixed_divs, ARRAY_SIZE(apmixed_fixed_divs), clk_data); diff --git a/drivers/clk/mediatek/clk-mt2712-apmixedsys.c b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c index a60622d251ff..54b18e9f83f8 100644 --- a/drivers/clk/mediatek/clk-mt2712-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c @@ -119,7 +119,7 @@ static int clk_mt2712_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); if (r) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt6735-apmixedsys.c b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c index e0949911e8f7..9e30c089a209 100644 --- a/drivers/clk/mediatek/clk-mt6735-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c @@ -93,8 +93,8 @@ static int clk_mt6735_apmixed_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, clk_data); - ret = mtk_clk_register_plls(pdev->dev.of_node, apmixedsys_plls, - ARRAY_SIZE(apmixedsys_plls), clk_data); + ret = mtk_clk_register_plls(&pdev->dev, apmixedsys_plls, + ARRAY_SIZE(apmixedsys_plls), clk_data); if (ret) { dev_err(&pdev->dev, "Failed to register PLLs: %d\n", ret); return ret; diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index d53731e7933f..60f6f9fa7dcf 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -740,7 +740,7 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c index 86732f5acf93..4b9dcb910b03 100644 --- a/drivers/clk/mediatek/clk-mt6779.c +++ b/drivers/clk/mediatek/clk-mt6779.c @@ -1220,7 +1220,7 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index fb59e71af58e..ebf850ac57f5 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -655,7 +655,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); } diff --git a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c index 2350592d9a93..8a29eaab0cfc 100644 --- a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c @@ -96,7 +96,7 @@ static int clk_mt7622_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data); if (ret) return ret; diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index baf94e7bea37..e154771b1b8b 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -634,7 +634,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, diff --git a/drivers/clk/mediatek/clk-mt7981-apmixed.c b/drivers/clk/mediatek/clk-mt7981-apmixed.c index e8211eb4e09e..6606b54fb376 100644 --- a/drivers/clk/mediatek/clk-mt7981-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c @@ -76,7 +76,7 @@ static int clk_mt7981_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (r) { diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c index 93751abe6be8..1c79418d08a7 100644 --- a/drivers/clk/mediatek/clk-mt7986-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c @@ -74,7 +74,7 @@ static int clk_mt7986_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (r) { diff --git a/drivers/clk/mediatek/clk-mt7988-apmixed.c b/drivers/clk/mediatek/clk-mt7988-apmixed.c index 63d33a78cb48..416a4b88d100 100644 --- a/drivers/clk/mediatek/clk-mt7988-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7988-apmixed.c @@ -86,7 +86,7 @@ static int clk_mt7988_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); if (r) goto free_apmixed_data; diff --git a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c index bdadc35c64cb..19e4ee489ec3 100644 --- a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c @@ -57,7 +57,8 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), + clk_data); if (ret) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt8167-apmixedsys.c b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c index adf576786696..fb6c21bbeef8 100644 --- a/drivers/clk/mediatek/clk-mt8167-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c @@ -105,7 +105,7 @@ static int clk_mt8167_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data); if (ret) return ret; diff --git a/drivers/clk/mediatek/clk-mt8183-apmixedsys.c b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c index 551adbfd7ac9..6242d4f5376e 100644 --- a/drivers/clk/mediatek/clk-mt8183-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c @@ -155,7 +155,7 @@ static int clk_mt8183_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data); if (ret) return ret; diff --git a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c index 21d7a9a2ab1a..a1de596bff99 100644 --- a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c @@ -106,7 +106,7 @@ static int clk_mt8188_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + r = mtk_clk_register_plls(&pdev->dev, plls, ARRAY_SIZE(plls), clk_data); if (r) goto free_apmixed_data; diff --git a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c index 8b45a3fad02f..a2d98ed58e34 100644 --- a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c +++ b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c @@ -66,7 +66,8 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); + r = mtk_clk_register_plls(&pdev->dev, apusys_plls, + ARRAY_SIZE(apusys_plls), clk_data); if (r) goto free_apusys_pll_data; diff --git a/drivers/clk/mediatek/clk-mt8196-apmixedsys.c b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c index 617f5449b88b..c4ebb0170b82 100644 --- a/drivers/clk/mediatek/clk-mt8196-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8196-apmixedsys.c @@ -152,7 +152,8 @@ static int clk_mt8196_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, mcd->clks, mcd->num_clks, clk_data); + r = mtk_clk_register_plls(&pdev->dev, mcd->clks, mcd->num_clks, + clk_data); if (r) goto free_apmixed_data; diff --git a/drivers/clk/mediatek/clk-mt8196-mcu.c b/drivers/clk/mediatek/clk-mt8196-mcu.c index 5cbcc411ae73..13642fc673c2 100644 --- a/drivers/clk/mediatek/clk-mt8196-mcu.c +++ b/drivers/clk/mediatek/clk-mt8196-mcu.c @@ -122,7 +122,7 @@ static int clk_mt8196_mcu_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, num_plls, clk_data); + r = mtk_clk_register_plls(&pdev->dev, plls, num_plls, clk_data); if (r) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c index ae1eb9de79ae..8e09c0f7b754 100644 --- a/drivers/clk/mediatek/clk-mt8196-mfg.c +++ b/drivers/clk/mediatek/clk-mt8196-mfg.c @@ -105,7 +105,7 @@ static int clk_mt8196_mfg_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, num_plls, clk_data); + r = mtk_clk_register_plls(&pdev->dev, plls, num_plls, clk_data); if (r) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt8196-vlpckgen.c b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c index d59a8a9d9855..7dcc164627c5 100644 --- a/drivers/clk/mediatek/clk-mt8196-vlpckgen.c +++ b/drivers/clk/mediatek/clk-mt8196-vlpckgen.c @@ -664,7 +664,7 @@ static int clk_mt8196_vlp_probe(struct platform_device *pdev) if (r) goto unregister_factors; - r = mtk_clk_register_plls(node, vlp_plls, ARRAY_SIZE(vlp_plls), + r = mtk_clk_register_plls(dev, vlp_plls, ARRAY_SIZE(vlp_plls), clk_data); if (r) goto unregister_muxes; diff --git a/drivers/clk/mediatek/clk-mt8365-apmixedsys.c b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c index f41b991a0178..e331aa28a4bd 100644 --- a/drivers/clk/mediatek/clk-mt8365-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c @@ -133,7 +133,7 @@ static int clk_mt8365_apmixed_probe(struct platform_device *pdev) return PTR_ERR(hw); clk_data->hws[CLK_APMIXED_USB20_EN] = hw; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data); if (ret) return ret; diff --git a/drivers/clk/mediatek/clk-mt8516-apmixedsys.c b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c index edd9174d2f2f..2a6206cae2f0 100644 --- a/drivers/clk/mediatek/clk-mt8516-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c @@ -87,7 +87,7 @@ static int clk_mt8516_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + ret = mtk_clk_register_plls(dev, plls, ARRAY_SIZE(plls), clk_data); if (ret) return ret; diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index cd2b6ce551c6..5caf91ae9ddb 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "clk-pll.h" @@ -404,7 +405,7 @@ void mtk_clk_unregister_pll(struct clk_hw *hw) kfree(pll); } -int mtk_clk_register_plls(struct device_node *node, +int mtk_clk_register_plls(struct device *dev, const struct mtk_pll_data *plls, int num_plls, struct clk_hw_onecell_data *clk_data) { @@ -412,7 +413,7 @@ int mtk_clk_register_plls(struct device_node *node, int i; struct clk_hw *hw; - base = of_iomap(node, 0); + base = of_iomap(dev->of_node, 0); if (!base) { pr_err("%s(): ioremap failed\n", __func__); return -EINVAL; @@ -423,7 +424,7 @@ int mtk_clk_register_plls(struct device_node *node, if (!IS_ERR_OR_NULL(clk_data->hws[pll->id])) { pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", - node, pll->id); + dev->of_node, pll->id); continue; } diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index d71c150ce83e..38fde1a273bf 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -10,9 +10,7 @@ #include #include -struct clk_ops; -struct clk_hw_onecell_data; -struct device_node; +struct device; struct mtk_pll_div_table { u32 div; @@ -78,9 +76,9 @@ struct mtk_clk_pll { const struct mtk_pll_data *data; }; -int mtk_clk_register_plls(struct device_node *node, - const struct mtk_pll_data *plls, int num_plls, - struct clk_hw_onecell_data *clk_data); +int mtk_clk_register_plls(struct device *dev, const struct mtk_pll_data *plls, + int num_plls, struct clk_hw_onecell_data *clk_data); + void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls, struct clk_hw_onecell_data *clk_data); From ecffd05839b32f17bde1f3701b68ab182a837b07 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 15 Dec 2025 11:24:00 +0100 Subject: [PATCH 33/38] clk: mediatek: Pass device to clk_hw_register for PLLs Passing the struct device pointer to clk_hw_register allows for runtime power management to work for the registered clock controllers. However, the mediatek PLL clocks do not do this. Change this by adding a struct device pointer argument to mtk_clk_register_pll, and fix up the only other user of it. Also add a new member to the struct mtk_clk_pll for the struct device pointer, which is set by mtk_clk_register_pll and is used by mtk_clk_register_pll_ops. If mtk_clk_register_pll is called with a NULL struct device pointer, then everything still works as expected; the clock core will simply treat them as previously, i.e. without runtime power management. Reviewed-by: Chen-Yu Tsai Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 9 ++++++--- drivers/clk/mediatek/clk-pll.h | 4 +++- drivers/clk/mediatek/clk-pllfh.c | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 5caf91ae9ddb..c4f9c06e5133 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -366,7 +366,7 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, init.parent_names = &parent_name; init.num_parents = 1; - ret = clk_hw_register(NULL, &pll->hw); + ret = clk_hw_register(pll->dev, &pll->hw); if (ret) return ERR_PTR(ret); @@ -374,7 +374,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, return &pll->hw; } -struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, +struct clk_hw *mtk_clk_register_pll(struct device *dev, + const struct mtk_pll_data *data, void __iomem *base) { struct mtk_clk_pll *pll; @@ -385,6 +386,8 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, if (!pll) return ERR_PTR(-ENOMEM); + pll->dev = dev; + hw = mtk_clk_register_pll_ops(pll, data, base, pll_ops); if (IS_ERR(hw)) kfree(pll); @@ -428,7 +431,7 @@ int mtk_clk_register_plls(struct device *dev, continue; } - hw = mtk_clk_register_pll(pll, base); + hw = mtk_clk_register_pll(dev, pll, base); if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", pll->name, diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index 38fde1a273bf..f6493699c4e3 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -61,6 +61,7 @@ struct mtk_pll_data { */ struct mtk_clk_pll { + struct device *dev; struct clk_hw hw; void __iomem *base_addr; void __iomem *pd_addr; @@ -108,7 +109,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, const struct mtk_pll_data *data, void __iomem *base, const struct clk_ops *pll_ops); -struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, +struct clk_hw *mtk_clk_register_pll(struct device *dev, + const struct mtk_pll_data *data, void __iomem *base); void mtk_clk_unregister_pll(struct clk_hw *hw); diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c index 83630ee07ee9..62bfe4a480f1 100644 --- a/drivers/clk/mediatek/clk-pllfh.c +++ b/drivers/clk/mediatek/clk-pllfh.c @@ -220,7 +220,7 @@ int mtk_clk_register_pllfhs(struct device_node *node, if (use_fhctl) hw = mtk_clk_register_pllfh(pll, pllfh, base); else - hw = mtk_clk_register_pll(pll, base); + hw = mtk_clk_register_pll(NULL, pll, base); if (IS_ERR(hw)) { pr_err("Failed to register %s clk %s: %ld\n", From 483f364bb0014495da19c1ccb1a6e2423fc37d95 Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 15 Dec 2025 11:24:01 +0100 Subject: [PATCH 34/38] clk: mediatek: Refactor pllfh registration to pass device After refactoring all of PLL to pass the device, it's now fairly easy to refactor pllfh and its users, as pllfh registration wraps PLL registration. Do this refactor and move all of the pllfh users to pass the device as well. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt6795-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8173-apmixedsys.c | 14 +++++++------- drivers/clk/mediatek/clk-mt8186-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8192-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-mt8195-apmixedsys.c | 2 +- drivers/clk/mediatek/clk-pllfh.c | 13 ++++++++----- drivers/clk/mediatek/clk-pllfh.h | 2 +- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c index 91665d7f125e..123d5d7fea85 100644 --- a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c @@ -152,7 +152,7 @@ static int clk_mt6795_apmixed_probe(struct platform_device *pdev) return -ENOMEM; fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); - ret = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + ret = mtk_clk_register_pllfhs(dev, plls, ARRAY_SIZE(plls), pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (ret) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c index 95385bb67d55..d7d416172ab3 100644 --- a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c @@ -140,13 +140,13 @@ MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_apmixed); static int clk_mt8173_apmixed_probe(struct platform_device *pdev) { const u8 *fhctl_node = "mediatek,mt8173-fhctl"; - struct device_node *node = pdev->dev.of_node; struct clk_hw_onecell_data *clk_data; + struct device *dev = &pdev->dev; void __iomem *base; struct clk_hw *hw; int r; - base = of_iomap(node, 0); + base = of_iomap(dev->of_node, 0); if (!base) return -ENOMEM; @@ -157,25 +157,25 @@ static int clk_mt8173_apmixed_probe(struct platform_device *pdev) } fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); - r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), - pllfhs, ARRAY_SIZE(pllfhs), clk_data); + r = mtk_clk_register_pllfhs(dev, plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_clk_data; hw = mtk_clk_register_ref2usb_tx("ref2usb_tx", "clk26m", base + REGOFF_REF2USB); if (IS_ERR(hw)) { r = PTR_ERR(hw); - dev_err(&pdev->dev, "Failed to register ref2usb_tx: %d\n", r); + dev_err(dev, "Failed to register ref2usb_tx: %d\n", r); goto unregister_plls; } clk_data->hws[CLK_APMIXED_REF2USB_TX] = hw; - hw = devm_clk_hw_register_divider(&pdev->dev, "hdmi_ref", "tvdpll_594m", 0, + hw = devm_clk_hw_register_divider(dev, "hdmi_ref", "tvdpll_594m", 0, base + REGOFF_HDMI_REF, 16, 3, CLK_DIVIDER_POWER_OF_TWO, NULL); clk_data->hws[CLK_APMIXED_HDMI_REF] = hw; - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + r = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, clk_data); if (r) goto unregister_ref2usb; diff --git a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c index 4b2b16578232..d35dd2632e43 100644 --- a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c @@ -151,7 +151,7 @@ static int clk_mt8186_apmixed_probe(struct platform_device *pdev) fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); - r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls), pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_apmixed_data; diff --git a/drivers/clk/mediatek/clk-mt8192-apmixedsys.c b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c index 0b66a27e4d5a..b0563a285bd6 100644 --- a/drivers/clk/mediatek/clk-mt8192-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c @@ -162,7 +162,7 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev) fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); - r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls), pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_clk_data; diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c index 282a3137dc89..44917ab034c5 100644 --- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c @@ -181,7 +181,7 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev) fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); - r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + r = mtk_clk_register_pllfhs(&pdev->dev, plls, ARRAY_SIZE(plls), pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_apmixed_data; diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c index 62bfe4a480f1..8ad11023d911 100644 --- a/drivers/clk/mediatek/clk-pllfh.c +++ b/drivers/clk/mediatek/clk-pllfh.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "clk-mtk.h" #include "clk-pllfh.h" @@ -149,7 +150,7 @@ static bool fhctl_is_supported_and_enabled(const struct mtk_pllfh_data *pllfh) } static struct clk_hw * -mtk_clk_register_pllfh(const struct mtk_pll_data *pll_data, +mtk_clk_register_pllfh(struct device *dev, const struct mtk_pll_data *pll_data, struct mtk_pllfh_data *pllfh_data, void __iomem *base) { struct clk_hw *hw; @@ -166,6 +167,8 @@ mtk_clk_register_pllfh(const struct mtk_pll_data *pll_data, goto out; } + fh->clk_pll.dev = dev; + hw = mtk_clk_register_pll_ops(&fh->clk_pll, pll_data, base, &mtk_pllfh_ops); @@ -194,7 +197,7 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw) kfree(fh); } -int mtk_clk_register_pllfhs(struct device_node *node, +int mtk_clk_register_pllfhs(struct device *dev, const struct mtk_pll_data *plls, int num_plls, struct mtk_pllfh_data *pllfhs, int num_fhs, struct clk_hw_onecell_data *clk_data) @@ -203,7 +206,7 @@ int mtk_clk_register_pllfhs(struct device_node *node, int i; struct clk_hw *hw; - base = of_iomap(node, 0); + base = of_iomap(dev->of_node, 0); if (!base) { pr_err("%s(): ioremap failed\n", __func__); return -EINVAL; @@ -218,9 +221,9 @@ int mtk_clk_register_pllfhs(struct device_node *node, use_fhctl = fhctl_is_supported_and_enabled(pllfh); if (use_fhctl) - hw = mtk_clk_register_pllfh(pll, pllfh, base); + hw = mtk_clk_register_pllfh(dev, pll, pllfh, base); else - hw = mtk_clk_register_pll(NULL, pll, base); + hw = mtk_clk_register_pll(dev, pll, base); if (IS_ERR(hw)) { pr_err("Failed to register %s clk %s: %ld\n", diff --git a/drivers/clk/mediatek/clk-pllfh.h b/drivers/clk/mediatek/clk-pllfh.h index 5f419c2ec01f..a4f337acad71 100644 --- a/drivers/clk/mediatek/clk-pllfh.h +++ b/drivers/clk/mediatek/clk-pllfh.h @@ -68,7 +68,7 @@ struct fh_operation { int (*ssc_enable)(struct mtk_fh *fh, u32 rate); }; -int mtk_clk_register_pllfhs(struct device_node *node, +int mtk_clk_register_pllfhs(struct device *dev, const struct mtk_pll_data *plls, int num_plls, struct mtk_pllfh_data *pllfhs, int num_pllfhs, struct clk_hw_onecell_data *clk_data); From 19024c9980c331908de0680283d572b80308654e Mon Sep 17 00:00:00 2001 From: Nicolas Frattaroli Date: Mon, 15 Dec 2025 11:24:02 +0100 Subject: [PATCH 35/38] clk: mediatek: Add mfg_eb as parent to mt8196 mfgpll clocks All the MFGPLL require MFG_EB to be on for any operation on them, and they only tick when MFG_EB is on as well, therefore making this a parent-child relationship. This dependency wasn't clear during the initial upstreaming of these clock controllers, as it only made itself known when I could observe the effects of the clock by bringing up a different piece of hardware. Add a new PLL_PARENT_EN flag to mediatek's clk-pll.h, and check for it when initialising the pll to then translate it into the actual CLK_OPS_PARENT_ENABLE flag. Then add the mfg_eb parent to the mfgpll clocks, and set the new PLL_PARENT_EN flag. Fixes: 03dc02f8c7dc ("clk: mediatek: Add MT8196 mfg clock support") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Nicolas Frattaroli Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8196-mfg.c | 13 +++++++------ drivers/clk/mediatek/clk-pll.c | 3 +++ drivers/clk/mediatek/clk-pll.h | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt8196-mfg.c b/drivers/clk/mediatek/clk-mt8196-mfg.c index 8e09c0f7b754..a317183f1681 100644 --- a/drivers/clk/mediatek/clk-mt8196-mfg.c +++ b/drivers/clk/mediatek/clk-mt8196-mfg.c @@ -58,24 +58,25 @@ .pcw_shift = _pcw_shift, \ .pcwbits = _pcwbits, \ .pcwibits = MT8196_INTEGER_BITS, \ + .parent_name = "mfg_eb", \ } static const struct mtk_pll_data mfg_ao_plls[] = { - PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, 0, - BIT(0), MFGPLL_CON1, 24, 0, 0, 0, + PLL(CLK_MFG_AO_MFGPLL, "mfgpll", MFGPLL_CON0, MFGPLL_CON0, 0, 0, + PLL_PARENT_EN, BIT(0), MFGPLL_CON1, 24, 0, 0, 0, MFGPLL_CON1, 0, 22), }; static const struct mtk_pll_data mfgsc0_ao_plls[] = { PLL(CLK_MFGSC0_AO_MFGPLL_SC0, "mfgpll-sc0", MFGPLL_SC0_CON0, - MFGPLL_SC0_CON0, 0, 0, 0, BIT(0), MFGPLL_SC0_CON1, 24, 0, 0, 0, - MFGPLL_SC0_CON1, 0, 22), + MFGPLL_SC0_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC0_CON1, 24, + 0, 0, 0, MFGPLL_SC0_CON1, 0, 22), }; static const struct mtk_pll_data mfgsc1_ao_plls[] = { PLL(CLK_MFGSC1_AO_MFGPLL_SC1, "mfgpll-sc1", MFGPLL_SC1_CON0, - MFGPLL_SC1_CON0, 0, 0, 0, BIT(0), MFGPLL_SC1_CON1, 24, 0, 0, 0, - MFGPLL_SC1_CON1, 0, 22), + MFGPLL_SC1_CON0, 0, 0, PLL_PARENT_EN, BIT(0), MFGPLL_SC1_CON1, 24, + 0, 0, 0, MFGPLL_SC1_CON1, 0, 22), }; static const struct of_device_id of_match_clk_mt8196_mfg[] = { diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index c4f9c06e5133..0f3759fcd9d0 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -359,6 +359,9 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, init.name = data->name; init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; + if (data->flags & PLL_PARENT_EN) + init.flags |= CLK_OPS_PARENT_ENABLE; + init.ops = pll_ops; if (data->parent_name) init.parent_names = &data->parent_name; diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index f6493699c4e3..f49dc2732ffe 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -19,6 +19,7 @@ struct mtk_pll_div_table { #define HAVE_RST_BAR BIT(0) #define PLL_AO BIT(1) +#define PLL_PARENT_EN BIT(2) #define POSTDIV_MASK GENMASK(2, 0) struct mtk_pll_data { From 963bb1866c2cf3f599dcf6d57bde35fb6fb42ec4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 22 Dec 2025 16:02:35 +0100 Subject: [PATCH 36/38] clk: mediatek: don't select clk-mt8192 for all ARM64 builds This option defaults to y for ARCH64 meaning it's built even if we don't want anything related to mediatek. Make the default condition stricter and only build it if ARCH_MEDIATEK is selected. Signed-off-by: Bartosz Golaszewski Reviewed-by: Brian Masney Reviewed-by: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 0e8dd82aa84e..2c09fd729bab 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -820,7 +820,7 @@ config COMMON_CLK_MT8192 depends on ARM64 || COMPILE_TEST select COMMON_CLK_MEDIATEK select COMMON_CLK_MEDIATEK_FHCTL - default ARM64 + default ARM64 && ARCH_MEDIATEK help This driver supports MediaTek MT8192 basic clocks. From aa2ad19210a6a444111bce55e8b69579f29318fb Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Sun, 23 Nov 2025 23:43:15 +0800 Subject: [PATCH 37/38] clk: mediatek: Fix error handling in runtime PM setup devm_pm_runtime_enable() can fail due to memory allocation. The current code ignores its return value, and when pm_runtime_resume_and_get() fails, it returns directly without unmapping the shared_io region. Add error handling for devm_pm_runtime_enable(). Reorder cleanup labels to properly unmap shared_io on pm_runtime_resume_and_get() failure. Fixes: 2f7b1d8b5505 ("clk: mediatek: Do a runtime PM get on controllers during probe") Signed-off-by: Haotian Zhang Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 19cd27941747..deafe55a96cb 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -497,14 +497,16 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, if (mcd->need_runtime_pm) { - devm_pm_runtime_enable(&pdev->dev); + r = devm_pm_runtime_enable(&pdev->dev); + if (r) + goto unmap_io; /* * Do a pm_runtime_resume_and_get() to workaround a possible * deadlock between clk_register() and the genpd framework. */ r = pm_runtime_resume_and_get(&pdev->dev); if (r) - return r; + goto unmap_io; } /* Calculate how many clk_hw_onecell_data entries to allocate */ @@ -618,11 +620,11 @@ static int __mtk_clk_simple_probe(struct platform_device *pdev, free_data: mtk_free_clk_data(clk_data); free_base: - if (mcd->shared_io && base) - iounmap(base); - if (mcd->need_runtime_pm) pm_runtime_put(&pdev->dev); +unmap_io: + if (mcd->shared_io && base) + iounmap(base); return r; } From 448b50b5cf12b7df254cae1d7ba3746e1acfc683 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 28 Jan 2026 11:01:34 -0800 Subject: [PATCH 38/38] Revert "clk: Respect CLK_OPS_PARENT_ENABLE during recalc" This reverts commit 669917676e93fca5ea3c66fc9539830312bec58e. It's been shown to cause problems on i.MX and STM32 platforms where the board doesn't boot. In one case, a clk with CLK_IS_CRITICAL and CLK_OPS_PARENT_ENABLE is being registered causing the parent to be enabled, the rate recalculated, and then the parent is disabled causing the critical clk being registered to stop clocking. A fix for that would be to calculate the rate of the clk after enabling the critical clk itself, but that wouldn't fix another problem where a clk with CLK_OPS_PARENT_ENABLE is registered before the parent is registered. In this case the hardware access in the clk_ops::recalc_rate() function would fail if the parent is disabled. There are even more problems exposed by this patch because it introduces logic that disables clks earlier in system boot than has existed previously. Historically we've not disabled clks until late init (clk_disable_unused) under the assumption that clks have been registered enough to have a consistent view of the clk tree. The clk_disable_unused logic doesn't work very well though, leading to quite a few devices booting with clk_ignore_unused on the kernel command line. Long story short, disabling clks during clk registration is full of pitfalls. Revert this commit until a proper solution can be found. Reported-by: Alexander Stein Closes: https://lore.kernel.org/r/6239343.lOV4Wx5bFT@steina-w Reported-by: Mark Brown Closes: https://lore.kernel.org/r/036da7ce-6487-4a6e-9b15-97c6d3bcdcec@sirena.org.uk Cc: Nicolas Frattaroli Cc: Brian Masney Cc: AngeloGioacchino Del Regno Cc: Chen-Yu Tsai Tested-by: Peng Fan Tested-by: Alexander Stein Reviewed-by: Brian Masney Tested-by: Mark Brown Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1b0f9d567f48..85d2f2481acf 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1921,14 +1921,7 @@ static unsigned long clk_recalc(struct clk_core *core, unsigned long rate = parent_rate; if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) { - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_prepare_enable(core->parent); - rate = core->ops->recalc_rate(core->hw, parent_rate); - - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_unprepare(core->parent); - clk_pm_runtime_put(core); } return rate; @@ -4038,9 +4031,6 @@ static int __clk_core_init(struct clk_core *core) */ clk_core_update_duty_cycle_nolock(core); - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_prepare_enable(core->parent); - /* * Set clk's rate. The preferred method is to use .recalc_rate. For * simple clocks and lazy developers the default fallback is to use the @@ -4056,9 +4046,6 @@ static int __clk_core_init(struct clk_core *core) rate = 0; core->rate = core->req_rate = rate; - if (core->flags & CLK_OPS_PARENT_ENABLE) - clk_core_disable_unprepare(core->parent); - /* * Enable CLK_IS_CRITICAL clocks so newly added critical clocks * don't get accidentally disabled when walking the orphan tree and