From fb20ccf70cf695f178d7c32e2d33b376560df0ff Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 17 Feb 2026 17:30:03 +0800 Subject: [PATCH 01/19] clk: sunxi-ng: sun55i-a523-r: Add missing r-spi module clock When the PRCM clk driver was added, somehow the r-spi module clock was skipped over. Add it so that r-spi can actually work. Fixes: 8cea339cfb81 ("clk: sunxi-ng: add support for the A523/T527 PRCM CCU") Reviewed-by: Andre Przywara Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260217093004.3239051-1-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c index 0339c4af0fe5..db0e36d8838e 100644 --- a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c @@ -83,9 +83,22 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(r_pwmctrl_clk, "r-pwmctrl", static SUNXI_CCU_GATE_HW(bus_r_pwmctrl_clk, "bus-r-pwmctrl", &r_apb0_clk.common.hw, 0x13c, BIT(0), 0); -/* SPI clock is /M/N (same as new MMC?) */ +static const struct clk_parent_data r_spi_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "pll-periph" }, + { .name = "pll-periph0-300M" }, + { .name = "pll-periph1-300M" }, + { .name = "pll-audio" }, +}; +static SUNXI_CCU_DUALDIV_MUX_GATE(r_spi_clk, "r-spi", r_spi_parents, 0x150, + 0, 5, /* M */ + 8, 5, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); static SUNXI_CCU_GATE_HW(bus_r_spi_clk, "bus-r-spi", &r_ahb_clk.common.hw, 0x15c, BIT(0), 0); + static SUNXI_CCU_GATE_HW(bus_r_spinlock_clk, "bus-r-spinlock", &r_ahb_clk.common.hw, 0x16c, BIT(0), 0); static SUNXI_CCU_GATE_HW(bus_r_msgbox_clk, "bus-r-msgbox", @@ -138,6 +151,7 @@ static struct ccu_common *sun55i_a523_r_ccu_clks[] = { &bus_r_twd_clk.common, &r_pwmctrl_clk.common, &bus_r_pwmctrl_clk.common, + &r_spi_clk.common, &bus_r_spi_clk.common, &bus_r_spinlock_clk.common, &bus_r_msgbox_clk.common, @@ -169,6 +183,7 @@ static struct clk_hw_onecell_data sun55i_a523_r_hw_clks = { [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw, [CLK_R_PWMCTRL] = &r_pwmctrl_clk.common.hw, [CLK_BUS_R_PWMCTRL] = &bus_r_pwmctrl_clk.common.hw, + [CLK_R_SPI] = &r_spi_clk.common.hw, [CLK_BUS_R_SPI] = &bus_r_spi_clk.common.hw, [CLK_BUS_R_SPINLOCK] = &bus_r_spinlock_clk.common.hw, [CLK_BUS_R_MSGBOX] = &bus_r_msgbox_clk.common.hw, From 75d627e5571a5ef313f6f553b7749b124c923c3d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 9 Feb 2026 23:26:19 -0300 Subject: [PATCH 02/19] dt-bindings: clock: rockchip: Add RV1103B CRU support Add support for the Rockchip RV1103B Clock and Reset Unit (CRU). The RV1103B CRU is compatible with the existing RV1126B binding. Add the compatible string to the schema and introduce the corresponding clock ID definitions. Signed-off-by: Fabio Estevam Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260210022620.172570-1-festevam@gmail.com Signed-off-by: Heiko Stuebner --- .../bindings/clock/rockchip,rv1126b-cru.yaml | 1 + .../dt-bindings/clock/rockchip,rv1103b-cru.h | 220 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 include/dt-bindings/clock/rockchip,rv1103b-cru.h diff --git a/Documentation/devicetree/bindings/clock/rockchip,rv1126b-cru.yaml b/Documentation/devicetree/bindings/clock/rockchip,rv1126b-cru.yaml index 04b0a5c51e4e..b6d3a04be8f1 100644 --- a/Documentation/devicetree/bindings/clock/rockchip,rv1126b-cru.yaml +++ b/Documentation/devicetree/bindings/clock/rockchip,rv1126b-cru.yaml @@ -17,6 +17,7 @@ description: properties: compatible: enum: + - rockchip,rv1103b-cru - rockchip,rv1126b-cru reg: diff --git a/include/dt-bindings/clock/rockchip,rv1103b-cru.h b/include/dt-bindings/clock/rockchip,rv1103b-cru.h new file mode 100644 index 000000000000..35afdee7e961 --- /dev/null +++ b/include/dt-bindings/clock/rockchip,rv1103b-cru.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Elaine Zhang + */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RV1103B_H +#define _DT_BINDINGS_CLK_ROCKCHIP_RV1103B_H + +#define PLL_GPLL 0 +#define ARMCLK 1 +#define PLL_DPLL 2 +#define XIN_OSC0_HALF 3 +#define CLK_GPLL_DIV24 4 +#define CLK_GPLL_DIV12 5 +#define CLK_GPLL_DIV6 6 +#define CLK_GPLL_DIV4 7 +#define CLK_GPLL_DIV3 8 +#define CLK_GPLL_DIV2P5 9 +#define CLK_GPLL_DIV2 10 +#define CLK_UART0_SRC 11 +#define CLK_UART1_SRC 12 +#define CLK_UART2_SRC 13 +#define CLK_UART0_FRAC 14 +#define CLK_UART1_FRAC 15 +#define CLK_UART2_FRAC 16 +#define CLK_SAI_SRC 17 +#define CLK_SAI_FRAC 18 +#define LSCLK_NPU_SRC 19 +#define CLK_NPU_SRC 20 +#define ACLK_VEPU_SRC 21 +#define CLK_VEPU_SRC 22 +#define ACLK_VI_SRC 23 +#define CLK_ISP_SRC 24 +#define DCLK_VICAP 25 +#define CCLK_EMMC 26 +#define CCLK_SDMMC0 27 +#define SCLK_SFC_2X 28 +#define LSCLK_PERI_SRC 29 +#define ACLK_PERI_SRC 30 +#define HCLK_HPMCU 31 +#define SCLK_UART0 32 +#define SCLK_UART1 33 +#define SCLK_UART2 34 +#define CLK_I2C_PMU 35 +#define CLK_I2C_PERI 36 +#define CLK_SPI0 37 +#define CLK_PWM0_SRC 38 +#define CLK_PWM1 39 +#define CLK_PWM2 40 +#define DCLK_DECOM_SRC 41 +#define CCLK_SDMMC1 42 +#define CLK_CORE_CRYPTO 43 +#define CLK_PKA_CRYPTO 44 +#define CLK_CORE_RGA 45 +#define MCLK_SAI_SRC 46 +#define CLK_FREQ_PWM0_SRC 47 +#define CLK_COUNTER_PWM0_SRC 48 +#define PCLK_TOP_ROOT 49 +#define CLK_REF_MIPI0 50 +#define CLK_MIPI0_OUT2IO 51 +#define CLK_REF_MIPI1 52 +#define CLK_MIPI1_OUT2IO 53 +#define MCLK_SAI_OUT2IO 54 +#define ACLK_NPU_ROOT 55 +#define HCLK_RKNN 56 +#define ACLK_RKNN 57 +#define LSCLK_VEPU_ROOT 58 +#define HCLK_VEPU 59 +#define ACLK_VEPU 60 +#define CLK_CORE_VEPU 61 +#define PCLK_IOC_VCCIO3 62 +#define PCLK_ACODEC 63 +#define PCLK_USBPHY 64 +#define LSCLK_VI_100M 65 +#define LSCLK_VI_ROOT 66 +#define HCLK_ISP 67 +#define ACLK_ISP 68 +#define CLK_CORE_ISP 69 +#define ACLK_VICAP 70 +#define HCLK_VICAP 71 +#define ISP0CLK_VICAP 72 +#define PCLK_CSI2HOST0 73 +#define PCLK_CSI2HOST1 74 +#define HCLK_EMMC 75 +#define HCLK_SFC 76 +#define HCLK_SFC_XIP 77 +#define HCLK_SDMMC0 78 +#define PCLK_CSIPHY 79 +#define PCLK_GPIO1 80 +#define DBCLK_GPIO1 81 +#define PCLK_IOC_VCCIO47 82 +#define LSCLK_DDR_ROOT 83 +#define CLK_TIMER_DDRMON 84 +#define LSCLK_PMU_ROOT 85 +#define PCLK_PMU 86 +#define XIN_RC_DIV 87 +#define CLK_32K 88 +#define PCLK_PMU_GPIO0 89 +#define DBCLK_PMU_GPIO0 90 +#define CLK_DDR_FAIL_SAFE 91 +#define PCLK_PMU_HP_TIMER 92 +#define CLK_PMU_32K_HP_TIMER 93 +#define PCLK_PWM0 94 +#define CLK_PWM0 95 +#define CLK_OSC_PWM0 96 +#define CLK_RC_PWM0 97 +#define CLK_FREQ_PWM0 98 +#define CLK_COUNTER_PWM0 99 +#define PCLK_I2C0 100 +#define CLK_I2C0 101 +#define PCLK_UART0 102 +#define PCLK_IOC_PMUIO0 103 +#define CLK_REFOUT 104 +#define CLK_PREROLL 105 +#define CLK_PREROLL_32K 106 +#define CLK_LPMCU_PMU 107 +#define PCLK_SPI2AHB 108 +#define HCLK_SPI2AHB 109 +#define SCLK_SPI2AHB 110 +#define PCLK_WDT_LPMCU 111 +#define TCLK_WDT_LPMCU 112 +#define HCLK_SFC_PMU1 113 +#define HCLK_SFC_XIP_PMU1 114 +#define SCLK_SFC_2X_PMU1 115 +#define CLK_LPMCU 116 +#define CLK_LPMCU_RTC 117 +#define PCLK_LPMCU_MAILBOX 118 +#define PCLK_IOC_PMUIO1 119 +#define PCLK_CRU_PMU1 120 +#define PCLK_PERI_ROOT 121 +#define PCLK_RTC_ROOT 122 +#define CLK_TIMER_ROOT 123 +#define PCLK_TIMER 124 +#define CLK_TIMER0 125 +#define CLK_TIMER1 126 +#define CLK_TIMER2 127 +#define CLK_TIMER3 128 +#define CLK_TIMER4 129 +#define CLK_TIMER5 130 +#define PCLK_STIMER 131 +#define CLK_STIMER0 132 +#define CLK_STIMER1 133 +#define PCLK_WDT_NS 134 +#define TCLK_WDT_NS 135 +#define PCLK_WDT_S 136 +#define TCLK_WDT_S 137 +#define PCLK_WDT_HPMCU 138 +#define TCLK_WDT_HPMCU 139 +#define PCLK_I2C1 140 +#define CLK_I2C1 141 +#define PCLK_I2C2 142 +#define CLK_I2C2 143 +#define PCLK_I2C3 144 +#define CLK_I2C3 145 +#define PCLK_I2C4 146 +#define CLK_I2C4 147 +#define PCLK_SPI0 148 +#define PCLK_PWM1 149 +#define CLK_OSC_PWM1 150 +#define PCLK_PWM2 151 +#define CLK_OSC_PWM2 152 +#define PCLK_UART2 153 +#define PCLK_UART1 154 +#define ACLK_RKDMA 155 +#define PCLK_TSADC 156 +#define CLK_TSADC 157 +#define CLK_TSADC_TSEN 158 +#define PCLK_SARADC 159 +#define CLK_SARADC 160 +#define PCLK_GPIO2 161 +#define DBCLK_GPIO2 162 +#define PCLK_IOC_VCCIO6 163 +#define ACLK_USBOTG 164 +#define CLK_REF_USBOTG 165 +#define HCLK_SDMMC1 166 +#define HCLK_SAI 167 +#define MCLK_SAI 168 +#define ACLK_CRYPTO 169 +#define HCLK_CRYPTO 170 +#define HCLK_RK_RNG_NS 171 +#define HCLK_RK_RNG_S 172 +#define PCLK_OTPC_NS 173 +#define CLK_OTPC_ROOT_NS 174 +#define CLK_SBPI_OTPC_NS 175 +#define CLK_USER_OTPC_NS 176 +#define PCLK_OTPC_S 177 +#define CLK_OTPC_ROOT_S 178 +#define CLK_SBPI_OTPC_S 179 +#define CLK_USER_OTPC_S 180 +#define CLK_OTPC_ARB 181 +#define PCLK_OTP_MASK 182 +#define HCLK_RGA 183 +#define ACLK_RGA 184 +#define ACLK_MAC 185 +#define PCLK_MAC 186 +#define CLK_MACPHY 187 +#define ACLK_SPINLOCK 188 +#define HCLK_CACHE 189 +#define PCLK_HPMCU_MAILBOX 190 +#define PCLK_HPMCU_INTMUX 191 +#define CLK_HPMCU 192 +#define CLK_HPMCU_RTC 193 +#define DCLK_DECOM 194 +#define ACLK_DECOM 195 +#define PCLK_DECOM 196 +#define ACLK_SYS_SRAM 197 +#define PCLK_DMA2DDR 198 +#define ACLK_DMA2DDR 199 +#define PCLK_DCF 200 +#define ACLK_DCF 201 +#define MCLK_ACODEC_TX 202 +#define SCLK_UART0_SRC 203 +#define SCLK_UART1_SRC 204 +#define SCLK_UART2_SRC 205 +#define XIN_RC_SRC 206 +#define CLK_UTMI_USBOTG 207 +#define CLK_REF_USBPHY 208 + +#endif // _DT_BINDINGS_CLK_ROCKCHIP_RV1103B_H From 3e65e426d4575a66a82928eb41b6d83f36e5ce9c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 9 Feb 2026 23:26:20 -0300 Subject: [PATCH 03/19] clk: rockchip: Add clock controller for the RV1103B Add the clock and reset tree definitions for the RV1103B SoC. Based on the 5.10 Rockchip vendor kernel driver. Signed-off-by: Fabio Estevam Link: https://patch.msgid.link/20260210022620.172570-2-festevam@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/Kconfig | 7 + drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-rv1103b.c | 658 +++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.h | 49 +++ 4 files changed, 715 insertions(+) create mode 100644 drivers/clk/rockchip/clk-rv1103b.c diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig index 5cf1e0fd6fb3..7e1433502061 100644 --- a/drivers/clk/rockchip/Kconfig +++ b/drivers/clk/rockchip/Kconfig @@ -16,6 +16,13 @@ config CLK_PX30 help Build the driver for PX30 Clock Driver. +config CLK_RV1103B + bool "Rockchip RV1103B clock controller support" + depends on ARM || COMPILE_TEST + default y + help + Build the driver for RV1103B Clock Driver. + config CLK_RV110X bool "Rockchip RV110x clock controller support" depends on ARM || COMPILE_TEST diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 4d8cbb2044c7..7c984ee006c6 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -18,6 +18,7 @@ clk-rockchip-y += gate-link.o clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-$(CONFIG_CLK_PX30) += clk-px30.o +obj-$(CONFIG_CLK_RV1103B) += clk-rv1103b.o obj-$(CONFIG_CLK_RV110X) += clk-rv1108.o obj-$(CONFIG_CLK_RV1126) += clk-rv1126.o obj-$(CONFIG_CLK_RV1126B) += clk-rv1126b.o rst-rv1126b.o diff --git a/drivers/clk/rockchip/clk-rv1103b.c b/drivers/clk/rockchip/clk-rv1103b.c new file mode 100644 index 000000000000..7da1fda5e1b9 --- /dev/null +++ b/drivers/clk/rockchip/clk-rv1103b.c @@ -0,0 +1,658 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Rockchip Electronics Co. Ltd. + * Author: Elaine Zhang + */ + +#include +#include +#include +#include +#include "clk.h" + +#define RV1103B_GRF_SOC_STATUS0 0x10 +#define RV1103B_FRAC_MAX_PRATE 1200000000 +#define PVTPLL_SRC_SEL_PVTPLL (BIT(0) | BIT(16)) + +enum rv1103b_plls { + dpll, + gpll, +}; + +static struct rockchip_pll_rate_table rv1103b_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0), + { /* sentinel */ }, +}; + +#define RV1103B_DIV_ACLK_CORE_MASK 0x1f +#define RV1103B_DIV_ACLK_CORE_SHIFT 0 +#define RV1103B_DIV_PCLK_DBG_MASK 0x1f +#define RV1103B_DIV_PCLK_DBG_SHIFT 8 + +#define RV1103B_CLKSEL0(_aclk_core) \ +{ \ + .reg = RV1103B_CORECLKSEL_CON(2), \ + .val = HIWORD_UPDATE(_aclk_core - 1, RV1103B_DIV_ACLK_CORE_MASK, \ + RV1103B_DIV_ACLK_CORE_SHIFT), \ +} + +#define RV1103B_CLKSEL1(_pclk_dbg) \ +{ \ + .reg = RV1103B_CORECLKSEL_CON(2), \ + .val = HIWORD_UPDATE(_pclk_dbg - 1, RV1103B_DIV_PCLK_DBG_MASK, \ + RV1103B_DIV_PCLK_DBG_SHIFT), \ +} + +#define RV1103B_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg) \ +{ \ + .prate = _prate, \ + .divs = { \ + RV1103B_CLKSEL0(_aclk_core), \ + RV1103B_CLKSEL1(_pclk_dbg), \ + }, \ +} + +static struct rockchip_cpuclk_rate_table rv1103b_cpuclk_rates[] __initdata = { + RV1103B_CPUCLK_RATE(1608000000, 4, 10), + RV1103B_CPUCLK_RATE(1512000000, 4, 10), + RV1103B_CPUCLK_RATE(1416000000, 4, 10), + RV1103B_CPUCLK_RATE(1296000000, 3, 10), + RV1103B_CPUCLK_RATE(1200000000, 3, 10), + RV1103B_CPUCLK_RATE(1188000000, 3, 8), + RV1103B_CPUCLK_RATE(1104000000, 2, 8), + RV1103B_CPUCLK_RATE(1008000000, 2, 8), + RV1103B_CPUCLK_RATE(816000000, 2, 6), + RV1103B_CPUCLK_RATE(600000000, 2, 4), + RV1103B_CPUCLK_RATE(594000000, 2, 4), + RV1103B_CPUCLK_RATE(408000000, 1, 3), + RV1103B_CPUCLK_RATE(396000000, 1, 3), +}; + +PNAME(mux_pll_p) = { "xin24m" }; +PNAME(mux_200m_100m_p) = { "clk_gpll_div6", "clk_gpll_div12" }; +PNAME(mux_gpll_24m_p) = { "gpll", "xin24m" }; +PNAME(mux_480m_400m_300m_200m_p) = { "clk_gpll_div2p5", "clk_gpll_div3", "clk_gpll_div4", "clk_gpll_div6" }; +PNAME(mux_480m_400m_300m_p) = { "clk_gpll_div2p5", "clk_gpll_div3", "clk_gpll_div4" }; +PNAME(mux_300m_200m_p) = { "clk_gpll_div4", "clk_gpll_div6" }; +PNAME(mux_600m_480m_400m_p) = { "clk_gpll_div2", "clk_gpll_div2p5", "clk_gpll_div3" }; +PNAME(mux_400m_300m_p) = { "clk_gpll_div3", "clk_gpll_div4" }; +PNAME(mux_100m_24m_p) = { "clk_gpll_div12", "xin24m" }; +PNAME(mux_200m_24m_p) = { "clk_gpll_div6", "xin24m" }; +PNAME(mux_200m_100m_50m_24m_p) = { "clk_gpll_div6", "clk_gpll_div12", "clk_gpll_div24", "xin24m" }; +PNAME(mux_300m_200m_100m_p) = { "clk_gpll_div4", "clk_gpll_div6", "clk_gpll_div12" }; +PNAME(sclk_uart0_src_p) = { "clk_uart0_src", "clk_uart0_frac", "xin24m" }; +PNAME(sclk_uart1_src_p) = { "clk_uart1_src", "clk_uart1_frac", "xin24m" }; +PNAME(sclk_uart2_src_p) = { "clk_uart2_src", "clk_uart2_frac", "xin24m" }; +PNAME(mclk_sai_src_p) = { "clk_sai_src", "clk_sai_frac", "mclk_sai_from_io", "xin_osc0_half" }; +PNAME(clk_freq_pwm0_src_p) = { "sclk_sai_from_io", "mclk_sai_from_io", "clk_testout_out" }; +PNAME(clk_counter_pwm0_src_p) = { "sclk_sai_from_io", "mclk_sai_from_io", "clk_testout_out" }; +PNAME(clk_mipi0_out2io_p) = { "clk_ref_mipi0", "xin24m" }; +PNAME(clk_mipi1_out2io_p) = { "clk_ref_mipi1", "xin24m" }; +PNAME(mclk_sai_out2io_p) = { "mclk_sai_src", "xin_osc0_half" }; +PNAME(aclk_npu_root_p) = { "clk_npu_src", "clk_npu_pvtpll" }; +PNAME(clk_core_vepu_p) = { "clk_vepu_src", "clk_vepu_pvtpll" }; +PNAME(lsclk_vi_root_p) = { "clk_gpll_div6", "lsclk_vi_100m" }; +PNAME(clk_core_isp_p) = { "clk_isp_src", "clk_isp_pvtpll_src" }; +PNAME(lsclk_pmu_root_p) = { "xin24m", "clk_rc_osc_io" }; +PNAME(xin_rc_div_p) = { "xin24m", "clk_rc_osc_io" }; +PNAME(clk_32k_p) = { "xin_rc_div", "clk_32k_rtc", "clk_32k_io" }; +PNAME(dbclk_pmu_gpio0_p) = { "xin24m", "clk_32k" }; +PNAME(sclk_sfc_2x_pmu1_p) = { "clk_gpll_div12", "clk_rc_osc_io" }; +PNAME(mux_armclk_p) = { "armclk_gpll", "clk_core_pvtpll" }; + +static struct rockchip_pll_clock rv1103b_pll_clks[] __initdata = { + [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p, + CLK_IS_CRITICAL, RV1103B_PLL_CON(16), + RV1103B_MODE_CON, 0, 10, 0, rv1103b_pll_rates), + [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p, + CLK_IS_CRITICAL, RV1103B_PLL_CON(24), + RV1103B_MODE_CON, 0, 10, 0, rv1103b_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) + +static struct rockchip_clk_branch rv1103b_clk_uart0_fracmux __initdata = + MUX(SCLK_UART0_SRC, "sclk_uart0_src", sclk_uart0_src_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(32), 8, 2, MFLAGS); + +static struct rockchip_clk_branch rv1103b_clk_uart1_fracmux __initdata = + MUX(SCLK_UART1_SRC, "sclk_uart1_src", sclk_uart1_src_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(32), 10, 2, MFLAGS); + +static struct rockchip_clk_branch rv1103b_clk_uart2_fracmux __initdata = + MUX(SCLK_UART2_SRC, "sclk_uart2_src", sclk_uart2_src_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(32), 12, 2, MFLAGS); + +static struct rockchip_clk_branch rv1103b_rcdiv_pmu_fracmux __initdata = + MUX(CLK_32K, "clk_32k", clk_32k_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3568_PMU_CLKSEL_CON(0), 0, 2, MFLAGS); + +static struct rockchip_clk_branch rv1103b_clk_branches[] __initdata = { + + /* Clock Definition */ + FACTOR(XIN_OSC0_HALF, "xin_osc0_half", "xin24m", 0, 1, 2), + + COMPOSITE_NOGATE(0, "armclk_gpll", mux_gpll_24m_p, CLK_IS_CRITICAL, + RV1103B_CLKSEL_CON(37), 12, 1, MFLAGS, 13, 3, DFLAGS), + + /* pd_top */ + COMPOSITE_NOMUX(CLK_GPLL_DIV24, "clk_gpll_div24", "gpll", 0, + RV1103B_CLKSEL_CON(0), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 0, GFLAGS), + COMPOSITE_NOMUX(CLK_GPLL_DIV12, "clk_gpll_div12", "gpll", 0, + RV1103B_CLKSEL_CON(0), 5, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 1, GFLAGS), + COMPOSITE_NOMUX(CLK_GPLL_DIV6, "clk_gpll_div6", "gpll", 0, + RV1103B_CLKSEL_CON(1), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 3, GFLAGS), + COMPOSITE_NOMUX(CLK_GPLL_DIV4, "clk_gpll_div4", "gpll", 0, + RV1103B_CLKSEL_CON(1), 10, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NOMUX(CLK_GPLL_DIV3, "clk_gpll_div3", "gpll", 0, + RV1103B_CLKSEL_CON(2), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 7, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(CLK_GPLL_DIV2P5, "clk_gpll_div2p5", "gpll", 0, + RV1103B_CLKSEL_CON(2), 5, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 8, GFLAGS), + COMPOSITE_NOMUX(CLK_GPLL_DIV2, "clk_gpll_div2", "gpll", 0, + RV1103B_CLKSEL_CON(2), 10, 5, DFLAGS, + RV1103B_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_NOMUX(CLK_UART0_SRC, "clk_uart0_src", "gpll", 0, + RV1103B_CLKSEL_CON(5), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(1), 0, GFLAGS), + COMPOSITE_NOMUX(CLK_UART1_SRC, "clk_uart1_src", "gpll", 0, + RV1103B_CLKSEL_CON(5), 5, 5, DFLAGS, + RV1103B_CLKGATE_CON(1), 1, GFLAGS), + COMPOSITE_NOMUX(CLK_UART2_SRC, "clk_uart2_src", "gpll", 0, + RV1103B_CLKSEL_CON(5), 10, 5, DFLAGS, + RV1103B_CLKGATE_CON(1), 2, GFLAGS), + COMPOSITE_FRACMUX(CLK_UART0_FRAC, "clk_uart0_frac", "clk_uart0_src", 0, + RV1103B_CLKSEL_CON(10), 0, + RV1103B_CLKGATE_CON(1), 6, GFLAGS, + &rv1103b_clk_uart0_fracmux), + COMPOSITE_FRACMUX(CLK_UART1_FRAC, "clk_uart1_frac", "clk_uart1_src", 0, + RV1103B_CLKSEL_CON(11), 0, + RV1103B_CLKGATE_CON(1), 7, GFLAGS, + &rv1103b_clk_uart1_fracmux), + COMPOSITE_FRACMUX(CLK_UART2_FRAC, "clk_uart2_frac", "clk_uart2_src", 0, + RV1103B_CLKSEL_CON(12), 0, + RV1103B_CLKGATE_CON(1), 8, GFLAGS, + &rv1103b_clk_uart2_fracmux), + GATE(SCLK_UART0, "sclk_uart0", "sclk_uart0_src", 0, + RV1103B_CLKGATE_CON(3), 3, GFLAGS), + GATE(SCLK_UART1, "sclk_uart1", "sclk_uart1_src", 0, + RV1103B_CLKGATE_CON(3), 4, GFLAGS), + GATE(SCLK_UART2, "sclk_uart2", "sclk_uart2_src", 0, + RV1103B_CLKGATE_CON(3), 8, GFLAGS), + + COMPOSITE_NOMUX(CLK_SAI_SRC, "clk_sai_src", "gpll", 0, + RV1103B_CLKSEL_CON(20), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(1), 12, GFLAGS), + MUX(MCLK_SAI_SRC, "mclk_sai_src", mclk_sai_src_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(35), 10, 2, MFLAGS), + GATE(MCLK_SAI, "mclk_sai", "mclk_sai_src", 0, + RV1103B_CLKGATE_CON(5), 5, GFLAGS), + + COMPOSITE_NODIV(LSCLK_NPU_SRC, "lsclk_npu_src", mux_200m_100m_p, CLK_IS_CRITICAL, + RV1103B_CLKSEL_CON(30), 0, 1, MFLAGS, + RV1103B_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE(CLK_NPU_SRC, "clk_npu_src", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(37), 0, 1, MFLAGS, 1, 2, DFLAGS, + RV1103B_CLKGATE_CON(5), 12, GFLAGS), + COMPOSITE_NODIV(ACLK_VEPU_SRC, "aclk_vepu_src", mux_480m_400m_300m_200m_p, 0, + RV1103B_CLKSEL_CON(30), 8, 2, MFLAGS, + RV1103B_CLKGATE_CON(2), 4, GFLAGS), + COMPOSITE(CLK_VEPU_SRC, "clk_vepu_src", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(37), 4, 1, MFLAGS, 5, 2, DFLAGS, + RV1103B_CLKGATE_CON(5), 13, GFLAGS), + COMPOSITE_NODIV(ACLK_VI_SRC, "aclk_vi_src", mux_480m_400m_300m_p, CLK_IS_CRITICAL, + RV1103B_CLKSEL_CON(30), 12, 2, MFLAGS, + RV1103B_CLKGATE_CON(2), 8, GFLAGS), + COMPOSITE(CLK_ISP_SRC, "clk_isp_src", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(37), 8, 1, MFLAGS, 9, 2, DFLAGS, + RV1103B_CLKGATE_CON(5), 14, GFLAGS), + COMPOSITE_NODIV(DCLK_VICAP, "dclk_vicap", mux_300m_200m_p, 0, + RV1103B_CLKSEL_CON(30), 14, 1, MFLAGS, + RV1103B_CLKGATE_CON(2), 9, GFLAGS), + COMPOSITE(CCLK_EMMC, "cclk_emmc", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(31), 15, 1, MFLAGS, 0, 8, DFLAGS, + RV1103B_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE(CCLK_SDMMC0, "cclk_sdmmc0", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(32), 15, 1, MFLAGS, 0, 8, DFLAGS, + RV1103B_CLKGATE_CON(2), 11, GFLAGS), + COMPOSITE(SCLK_SFC_2X, "sclk_sfc_2x", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(33), 15, 1, MFLAGS, 0, 8, DFLAGS, + RV1103B_CLKGATE_CON(2), 12, GFLAGS), + COMPOSITE_NODIV(LSCLK_PERI_SRC, "lsclk_peri_src", mux_300m_200m_p, CLK_IS_CRITICAL, + RV1103B_CLKSEL_CON(31), 9, 1, MFLAGS, + RV1103B_CLKGATE_CON(3), 0, GFLAGS), + COMPOSITE_NODIV(ACLK_PERI_SRC, "aclk_peri_src", mux_600m_480m_400m_p, CLK_IS_CRITICAL, + RV1103B_CLKSEL_CON(31), 10, 2, MFLAGS, + RV1103B_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE_NODIV(HCLK_HPMCU, "hclk_hpmcu", mux_400m_300m_p, 0, + RV1103B_CLKSEL_CON(31), 12, 1, MFLAGS, + RV1103B_CLKGATE_CON(3), 2, GFLAGS), + COMPOSITE_NODIV(CLK_I2C_PMU, "clk_i2c_pmu", mux_100m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 0, 1, MFLAGS, + RV1103B_CLKGATE_CON(4), 0, GFLAGS), + COMPOSITE_NODIV(CLK_I2C_PERI, "clk_i2c_peri", mux_200m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 1, 1, MFLAGS, + RV1103B_CLKGATE_CON(4), 4, GFLAGS), + COMPOSITE_NODIV(CLK_SPI0, "clk_spi0", mux_200m_100m_50m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 2, 2, MFLAGS, + RV1103B_CLKGATE_CON(4), 5, GFLAGS), + COMPOSITE_NODIV(CLK_PWM0_SRC, "clk_pwm0_src", mux_100m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 12, 1, MFLAGS, + RV1103B_CLKGATE_CON(4), 10, GFLAGS), + COMPOSITE_NODIV(CLK_PWM1, "clk_pwm1", mux_100m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 13, 1, MFLAGS, + RV1103B_CLKGATE_CON(4), 11, GFLAGS), + COMPOSITE_NODIV(CLK_PWM2, "clk_pwm2", mux_100m_24m_p, 0, + RV1103B_CLKSEL_CON(34), 14, 1, MFLAGS, + RV1103B_CLKGATE_CON(4), 12, GFLAGS), + COMPOSITE_NODIV(DCLK_DECOM_SRC, "dclk_decom_src", mux_480m_400m_300m_p, 0, + RV1103B_CLKSEL_CON(35), 0, 2, MFLAGS, + RV1103B_CLKGATE_CON(5), 0, GFLAGS), + COMPOSITE(CCLK_SDMMC1, "cclk_sdmmc1", mux_gpll_24m_p, 0, + RV1103B_CLKSEL_CON(36), 15, 1, MFLAGS, 0, 8, DFLAGS, + RV1103B_CLKGATE_CON(5), 1, GFLAGS), + COMPOSITE_NODIV(CLK_CORE_CRYPTO, "clk_core_crypto", mux_300m_200m_100m_p, 0, + RV1103B_CLKSEL_CON(35), 2, 2, MFLAGS, + RV1103B_CLKGATE_CON(5), 2, GFLAGS), + COMPOSITE_NODIV(CLK_PKA_CRYPTO, "clk_pka_crypto", mux_300m_200m_100m_p, 0, + RV1103B_CLKSEL_CON(35), 4, 2, MFLAGS, + RV1103B_CLKGATE_CON(5), 3, GFLAGS), + COMPOSITE_NODIV(CLK_CORE_RGA, "clk_core_rga", mux_400m_300m_p, 0, + RV1103B_CLKSEL_CON(35), 8, 1, MFLAGS, + RV1103B_CLKGATE_CON(5), 4, GFLAGS), + + GATE(PCLK_TOP_ROOT, "pclk_top_root", "clk_gpll_div12", CLK_IS_CRITICAL, + RV1103B_CLKGATE_CON(6), 0, GFLAGS), + COMPOSITE_NOMUX(CLK_REF_MIPI0, "clk_ref_mipi0", "clk_gpll_div2", 0, + RV1103B_CLKSEL_CON(40), 0, 5, DFLAGS, + RV1103B_CLKGATE_CON(6), 3, GFLAGS), + COMPOSITE_NODIV(CLK_MIPI0_OUT2IO, "clk_mipi0_out2io", clk_mipi0_out2io_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(40), 6, 1, MFLAGS, + RV1103B_CLKGATE_CON(6), 4, GFLAGS), + COMPOSITE_NOMUX(CLK_REF_MIPI1, "clk_ref_mipi1", "clk_gpll_div2", 0, + RV1103B_CLKSEL_CON(40), 8, 5, DFLAGS, + RV1103B_CLKGATE_CON(6), 5, GFLAGS), + COMPOSITE_NODIV(CLK_MIPI1_OUT2IO, "clk_mipi1_out2io", clk_mipi1_out2io_p, CLK_SET_RATE_PARENT, + RV1103B_CLKSEL_CON(40), 14, 1, MFLAGS, + RV1103B_CLKGATE_CON(6), 6, GFLAGS), + COMPOSITE(MCLK_SAI_OUT2IO, "mclk_sai_out2io", mclk_sai_out2io_p, 0, + RV1103B_CLKSEL_CON(41), 7, 1, MFLAGS, 13, 3, DFLAGS, + RV1103B_CLKGATE_CON(6), 9, GFLAGS), + + /* pd_vpu */ + COMPOSITE_NODIV(ACLK_NPU_ROOT, "aclk_npu_root", aclk_npu_root_p, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + RV1103B_NPUCLKSEL_CON(0), 1, 1, MFLAGS, + RV1103B_NPUCLKGATE_CON(0), 1, GFLAGS), + GATE(HCLK_RKNN, "hclk_rknn", "lsclk_npu_src", 0, + RV1103B_NPUCLKGATE_CON(0), 4, GFLAGS), + GATE(ACLK_RKNN, "aclk_rknn", "aclk_npu_root", 0, + RV1103B_NPUCLKGATE_CON(0), 5, GFLAGS), + + /* pd_vepu */ + COMPOSITE_NOMUX(LSCLK_VEPU_ROOT, "lsclk_vepu_root", "aclk_vepu_src", CLK_IS_CRITICAL, + RV1103B_VEPUCLKSEL_CON(0), 2, 2, DFLAGS, + RV1103B_VEPUCLKGATE_CON(0), 0, GFLAGS), + GATE(HCLK_VEPU, "hclk_vepu", "lsclk_vepu_root", 0, + RV1103B_VEPUCLKGATE_CON(0), 4, GFLAGS), + GATE(ACLK_VEPU, "aclk_vepu", "aclk_vepu_src", 0, + RV1103B_VEPUCLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NODIV(CLK_CORE_VEPU, "clk_core_vepu", clk_core_vepu_p, 0, + RV1103B_VEPUCLKSEL_CON(0), 1, 1, MFLAGS, + RV1103B_VEPUCLKGATE_CON(0), 6, GFLAGS), + GATE(PCLK_ACODEC, "pclk_acodec", "lsclk_vepu_root", 0, + RV1103B_VEPUCLKGATE_CON(0), 13, GFLAGS), + GATE(PCLK_USBPHY, "pclk_usbphy", "lsclk_vepu_root", 0, + RV1103B_VEPUCLKGATE_CON(0), 14, GFLAGS), + + /* pd_vi */ + FACTOR(LSCLK_VI_100M, "lsclk_vi_100m", "clk_gpll_div6", 0, 1, 2), + COMPOSITE_NODIV(LSCLK_VI_ROOT, "lsclk_vi_root", lsclk_vi_root_p, CLK_IS_CRITICAL, + RV1103B_VICLKSEL_CON(0), 3, 1, MFLAGS, + RV1103B_VICLKGATE_CON(0), 0, GFLAGS), + GATE(HCLK_ISP, "hclk_isp", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(0), 4, GFLAGS), + GATE(ACLK_ISP, "aclk_isp", "aclk_vi_src", 0, + RV1103B_VICLKGATE_CON(0), 5, GFLAGS), + COMPOSITE_NODIV(CLK_CORE_ISP, "clk_core_isp", clk_core_isp_p, 0, + RV1103B_VICLKSEL_CON(0), 1, 1, MFLAGS, + RV1103B_VICLKGATE_CON(0), 6, GFLAGS), + GATE(ACLK_VICAP, "aclk_vicap", "aclk_vi_src", 0, + RV1103B_VICLKGATE_CON(1), 2, GFLAGS), + GATE(HCLK_VICAP, "hclk_vicap", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 3, GFLAGS), + GATE(ISP0CLK_VICAP, "isp0clk_vicap", "clk_core_isp", 0, + RV1103B_VICLKGATE_CON(1), 8, GFLAGS), + GATE(PCLK_CSI2HOST0, "pclk_csi2host0", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 9, GFLAGS), + GATE(PCLK_CSI2HOST1, "pclk_csi2host1", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 11, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 13, GFLAGS), + GATE(HCLK_SFC, "hclk_sfc", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 14, GFLAGS), + GATE(HCLK_SFC_XIP, "hclk_sfc_xip", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(1), 15, GFLAGS), + GATE(HCLK_SDMMC0, "hclk_sdmmc0", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(2), 0, GFLAGS), + GATE(PCLK_CSIPHY, "pclk_csiphy", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(2), 2, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "lsclk_vi_root", 0, + RV1103B_VICLKGATE_CON(2), 3, GFLAGS), + GATE(DBCLK_GPIO1, "dbclk_gpio1", "xin24m", 0, + RV1103B_VICLKGATE_CON(2), 4, GFLAGS), + + /* pd_ddr */ + GATE(LSCLK_DDR_ROOT, "lsclk_ddr_root", "clk_gpll_div12", CLK_IS_CRITICAL, + RV1103B_DDRCLKGATE_CON(0), 0, GFLAGS), + GATE(CLK_TIMER_DDRMON, "clk_timer_ddrmon", "xin24m", 0, + RV1103B_DDRCLKGATE_CON(0), 4, GFLAGS), + FACTOR(0, "sclk_ddr", "dpll", 0, 1, 2), + + /* pd_pmu */ + COMPOSITE(LSCLK_PMU_ROOT, "lsclk_pmu_root", lsclk_pmu_root_p, CLK_IS_CRITICAL, + RV1103B_PMUCLKSEL_CON(2), 4, 1, MFLAGS, 0, 2, DFLAGS, + RV1103B_PMUCLKGATE_CON(0), 0, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "lsclk_pmu_root", CLK_IS_CRITICAL, + RV1103B_PMUCLKGATE_CON(0), 2, GFLAGS), + MUX(XIN_RC_SRC, "xin_rc_src", xin_rc_div_p, 0, + RV1103B_PMUCLKSEL_CON(0), 2, 1, MFLAGS), + COMPOSITE_FRACMUX(XIN_RC_DIV, "xin_rc_div", "xin_rc_src", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + RV1103B_PMUCLKSEL_CON(1), 0, + RV1103B_PMUCLKGATE_CON(0), 3, GFLAGS, + &rv1103b_rcdiv_pmu_fracmux), + GATE(PCLK_PMU_GPIO0, "pclk_pmu_gpio0", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(0), 4, GFLAGS), + COMPOSITE_NODIV(DBCLK_PMU_GPIO0, "dbclk_pmu_gpio0", dbclk_pmu_gpio0_p, 0, + RK3568_PMU_CLKSEL_CON(0), 3, 1, MFLAGS, + RV1103B_PMUCLKGATE_CON(0), 5, GFLAGS), + GATE(PCLK_PWM0, "pclk_pwm0", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(2), 0, GFLAGS), + GATE(CLK_PWM0, "clk_pwm0", "clk_pwm0_src", 0, + RV1103B_PMUCLKGATE_CON(2), 1, GFLAGS), + GATE(CLK_OSC_PWM0, "clk_osc_pwm0", "xin24m", 0, + RV1103B_PMUCLKGATE_CON(2), 2, GFLAGS), + GATE(CLK_RC_PWM0, "clk_rc_pwm0", "clk_32k", 0, + RV1103B_PMUCLKGATE_CON(2), 3, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(0), 12, GFLAGS), + GATE(CLK_I2C0, "clk_i2c0", "clk_i2c_pmu", 0, + RV1103B_PMUCLKGATE_CON(0), 13, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(0), 14, GFLAGS), + GATE(CLK_REFOUT, "clk_refout", "xin24m", 0, + RV1103B_PMUCLKGATE_CON(1), 4, GFLAGS), + GATE(CLK_PREROLL, "clk_preroll", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(1), 6, GFLAGS), + GATE(CLK_PREROLL_32K, "clk_preroll_32k", "clk_32k", 0, + RV1103B_PMUCLKGATE_CON(1), 7, GFLAGS), + GATE(CLK_LPMCU_PMU, "clk_lpmcu_pmu", "lsclk_pmu_root", 0, + RV1103B_PMUCLKGATE_CON(2), 12, GFLAGS), + + /* pd_pmu1 */ + GATE(PCLK_SPI2AHB, "pclk_spi2ahb", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(0), 0, GFLAGS), + GATE(HCLK_SPI2AHB, "hclk_spi2ahb", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(0), 1, GFLAGS), + GATE(PCLK_WDT_LPMCU, "pclk_wdt_lpmcu", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(0), 9, GFLAGS), + GATE(TCLK_WDT_LPMCU, "tclk_wdt_lpmcu", "xin24m", 0, + RV1103B_PMU1CLKGATE_CON(0), 10, GFLAGS), + GATE(HCLK_SFC_PMU1, "hclk_sfc_pmu1", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(0), 12, GFLAGS), + GATE(HCLK_SFC_XIP_PMU1, "hclk_sfc_xip_pmu1", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(0), 13, GFLAGS), + COMPOSITE_NODIV(SCLK_SFC_2X_PMU1, "sclk_sfc_2x_pmu1", sclk_sfc_2x_pmu1_p, 0, + RV1103B_PMU1CLKSEL_CON(0), 8, 1, MFLAGS, + RV1103B_PMU1CLKGATE_CON(0), 14, GFLAGS), + GATE(CLK_LPMCU, "clk_lpmcu", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(1), 0, GFLAGS), + GATE(CLK_LPMCU_RTC, "clk_lpmcu_rtc", "xin24m", 0, + RV1103B_PMU1CLKGATE_CON(1), 4, GFLAGS), + GATE(PCLK_LPMCU_MAILBOX, "pclk_lpmcu_mailbox", "lsclk_pmu_root", 0, + RV1103B_PMU1CLKGATE_CON(1), 8, GFLAGS), + + /* pd_peri */ + COMPOSITE_NOMUX(PCLK_PERI_ROOT, "pclk_peri_root", "lsclk_peri_src", CLK_IS_CRITICAL, + RV1103B_PERICLKSEL_CON(0), 0, 2, DFLAGS, + RV1103B_PERICLKGATE_CON(0), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_RTC_ROOT, "pclk_rtc_root", "lsclk_peri_src", CLK_IS_CRITICAL, + RV1103B_PERICLKSEL_CON(2), 12, 4, DFLAGS, + RV1103B_PERICLKGATE_CON(0), 8, GFLAGS), + GATE(CLK_TIMER_ROOT, "clk_timer_root", "xin24m", 0, + RV1103B_PERICLKGATE_CON(0), 1, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(1), 0, GFLAGS), + GATE(CLK_TIMER0, "clk_timer0", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 1, GFLAGS), + GATE(CLK_TIMER1, "clk_timer1", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 2, GFLAGS), + GATE(CLK_TIMER2, "clk_timer2", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 3, GFLAGS), + GATE(CLK_TIMER3, "clk_timer3", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 4, GFLAGS), + GATE(CLK_TIMER4, "clk_timer4", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 5, GFLAGS), + GATE(CLK_TIMER5, "clk_timer5", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 6, GFLAGS), + GATE(PCLK_STIMER, "pclk_stimer", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(1), 7, GFLAGS), + GATE(CLK_STIMER0, "clk_stimer0", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 8, GFLAGS), + GATE(CLK_STIMER1, "clk_stimer1", "clk_timer_root", 0, + RV1103B_PERICLKGATE_CON(1), 9, GFLAGS), + GATE(PCLK_WDT_NS, "pclk_wdt_ns", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 0, GFLAGS), + GATE(TCLK_WDT_NS, "tclk_wdt_ns", "xin24m", 0, + RV1103B_PERICLKGATE_CON(2), 1, GFLAGS), + GATE(PCLK_WDT_S, "pclk_wdt_s", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 2, GFLAGS), + GATE(TCLK_WDT_S, "tclk_wdt_s", "xin24m", 0, + RV1103B_PERICLKGATE_CON(2), 3, GFLAGS), + GATE(PCLK_WDT_HPMCU, "pclk_wdt_hpmcu", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 4, GFLAGS), + GATE(TCLK_WDT_HPMCU, "tclk_wdt_hpmcu", "xin24m", 0, + RV1103B_PERICLKGATE_CON(2), 5, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 6, GFLAGS), + GATE(CLK_I2C1, "clk_i2c1", "clk_i2c_peri", 0, + RV1103B_PERICLKGATE_CON(2), 7, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 8, GFLAGS), + GATE(CLK_I2C2, "clk_i2c2", "clk_i2c_peri", 0, + RV1103B_PERICLKGATE_CON(2), 9, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 10, GFLAGS), + GATE(CLK_I2C3, "clk_i2c3", "clk_i2c_peri", 0, + RV1103B_PERICLKGATE_CON(2), 11, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(2), 12, GFLAGS), + GATE(CLK_I2C4, "clk_i2c4", "clk_i2c_peri", 0, + RV1103B_PERICLKGATE_CON(2), 13, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(3), 10, GFLAGS), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(4), 6, GFLAGS), + GATE(CLK_OSC_PWM1, "clk_osc_pwm1", "xin24m", 0, + RV1103B_PERICLKGATE_CON(4), 8, GFLAGS), + GATE(PCLK_PWM2, "pclk_pwm2", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(4), 12, GFLAGS), + GATE(CLK_OSC_PWM2, "clk_osc_pwm2", "xin24m", 0, + RV1103B_PERICLKGATE_CON(4), 13, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(3), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(3), 2, GFLAGS), + GATE(ACLK_RKDMA, "aclk_rkdma", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(5), 8, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(5), 9, GFLAGS), + COMPOSITE_NOMUX(CLK_TSADC, "clk_tsadc", "xin24m", 0, + RV1103B_PERICLKSEL_CON(0), 4, 5, DFLAGS, + RV1103B_PERICLKGATE_CON(5), 10, GFLAGS), + COMPOSITE_NOMUX(CLK_TSADC_TSEN, "clk_tsadc_tsen", "xin24m", 0, + RV1103B_PERICLKSEL_CON(0), 10, 5, DFLAGS, + RV1103B_PERICLKGATE_CON(5), 11, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(5), 12, GFLAGS), + COMPOSITE_NOMUX(CLK_SARADC, "clk_saradc", "xin24m", 0, + RV1103B_PERICLKSEL_CON(1), 0, 3, DFLAGS, + RV1103B_PERICLKGATE_CON(5), 13, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(6), 3, GFLAGS), + GATE(DBCLK_GPIO2, "dbclk_gpio2", "xin24m", 0, + RV1103B_PERICLKGATE_CON(6), 4, GFLAGS), + GATE(ACLK_USBOTG, "aclk_usbotg", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(6), 9, GFLAGS), + GATE(CLK_REF_USBOTG, "clk_ref_usbotg", "xin24m", 0, + RV1103B_PERICLKGATE_CON(6), 10, GFLAGS), + GATE(HCLK_SDMMC1, "hclk_sdmmc1", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(7), 0, GFLAGS), + GATE(HCLK_SAI, "hclk_sai", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(7), 1, GFLAGS), + GATE(ACLK_CRYPTO, "aclk_crypto", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(8), 2, GFLAGS), + GATE(HCLK_CRYPTO, "hclk_crypto", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(8), 3, GFLAGS), + GATE(HCLK_RK_RNG_S, "hclk_rk_rng_s", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(8), 5, GFLAGS), + GATE(HCLK_RK_RNG_NS, "hclk_rk_rng_ns", "hclk_rk_rng_s", 0, + RV1103B_PERICLKGATE_CON(8), 4, GFLAGS), + GATE(PCLK_OTPC_NS, "pclk_otpc_ns", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(8), 6, GFLAGS), + GATE(CLK_OTPC_ROOT_NS, "clk_otpc_root_ns", "xin24m", 0, + RV1103B_PERICLKGATE_CON(8), 7, GFLAGS), + GATE(CLK_SBPI_OTPC_NS, "clk_sbpi_otpc_ns", "clk_otpc_root_ns", 0, + RV1103B_PERICLKGATE_CON(8), 8, GFLAGS), + COMPOSITE_NOMUX(CLK_USER_OTPC_NS, "clk_user_otpc_ns", "clk_otpc_root_ns", 0, + RV1103B_PERICLKSEL_CON(1), 4, 3, DFLAGS, + RV1103B_PERICLKGATE_CON(8), 9, GFLAGS), + GATE(PCLK_OTPC_S, "pclk_otpc_s", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(8), 10, GFLAGS), + GATE(CLK_OTPC_ROOT_S, "clk_otpc_root_s", "xin24m", 0, + RV1103B_PERICLKGATE_CON(8), 11, GFLAGS), + GATE(CLK_SBPI_OTPC_S, "clk_sbpi_otpc_s", "clk_otpc_root_s", 0, + RV1103B_PERICLKGATE_CON(8), 12, GFLAGS), + COMPOSITE_NOMUX(CLK_USER_OTPC_S, "clk_user_otpc_s", "clk_otpc_root_s", 0, + RV1103B_PERICLKSEL_CON(1), 8, 3, DFLAGS, + RV1103B_PERICLKGATE_CON(8), 13, GFLAGS), + GATE(PCLK_OTP_MASK, "pclk_otp_mask", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(8), 15, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(9), 0, GFLAGS), + GATE(ACLK_RGA, "aclk_rga", "aclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(9), 1, GFLAGS), + GATE(ACLK_MAC, "aclk_mac", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(9), 3, GFLAGS), + GATE(PCLK_MAC, "pclk_mac", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(9), 4, GFLAGS), + GATE(CLK_MACPHY, "clk_macphy", "xin24m", 0, + RV1103B_PERICLKGATE_CON(9), 11, GFLAGS), + GATE(ACLK_SPINLOCK, "aclk_spinlock", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(10), 0, GFLAGS), + GATE(HCLK_CACHE, "hclk_cache", "hclk_hpmcu", 0, + RV1103B_PERICLKGATE_CON(10), 1, GFLAGS), + GATE(PCLK_HPMCU_MAILBOX, "pclk_hpmcu_mailbox", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(10), 2, GFLAGS), + GATE(PCLK_HPMCU_INTMUX, "pclk_hpmcu_intmux", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(10), 3, GFLAGS), + GATE(CLK_HPMCU, "clk_hpmcu", "hclk_hpmcu", 0, + RV1103B_PERICLKGATE_CON(10), 4, GFLAGS), + GATE(CLK_HPMCU_RTC, "clk_hpmcu_rtc", "xin24m", 0, + RV1103B_PERICLKGATE_CON(10), 8, GFLAGS), + GATE(DCLK_DECOM, "dclk_decom", "dclk_decom_src", 0, + RV1103B_PERICLKGATE_CON(11), 0, GFLAGS), + GATE(ACLK_DECOM, "aclk_decom", "aclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(11), 1, GFLAGS), + GATE(PCLK_DECOM, "pclk_decom", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(11), 2, GFLAGS), + GATE(ACLK_SYS_SRAM, "aclk_sys_sram", "lsclk_peri_src", CLK_IS_CRITICAL, + RV1103B_PERICLKGATE_CON(11), 3, GFLAGS), + GATE(PCLK_DMA2DDR, "pclk_dma2ddr", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(11), 4, GFLAGS), + GATE(ACLK_DMA2DDR, "aclk_dma2ddr", "aclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(11), 5, GFLAGS), + GATE(PCLK_DCF, "pclk_dcf", "pclk_peri_root", 0, + RV1103B_PERICLKGATE_CON(11), 6, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "lsclk_peri_src", 0, + RV1103B_PERICLKGATE_CON(11), 7, GFLAGS), + COMPOSITE_NOMUX(MCLK_ACODEC_TX, "mclk_acodec_tx", "mclk_sai_src", 0, + RV1103B_PERICLKSEL_CON(2), 0, 3, DFLAGS, + RV1103B_PERICLKGATE_CON(11), 9, GFLAGS), + GATE(CLK_REF_USBPHY, "clk_ref_usbphy", "xin24m", 0, + RV1103B_PERICLKGATE_CON(11), 12, GFLAGS), + + /* io */ + COMPOSITE_NODIV(CLK_FREQ_PWM0_SRC, "clk_freq_pwm0_src", clk_freq_pwm0_src_p, 0, + RV1103B_CLKSEL_CON(35), 12, 2, MFLAGS, + RV1103B_CLKGATE_CON(5), 6, GFLAGS), + GATE(CLK_FREQ_PWM0, "clk_freq_pwm0", "clk_freq_pwm0_src", 0, + RV1103B_PMUCLKGATE_CON(2), 4, GFLAGS), + COMPOSITE_NODIV(CLK_COUNTER_PWM0_SRC, "clk_counter_pwm0_src", clk_counter_pwm0_src_p, 0, + RV1103B_CLKSEL_CON(35), 14, 2, MFLAGS, + RV1103B_CLKGATE_CON(5), 7, GFLAGS), + GATE(CLK_COUNTER_PWM0, "clk_counter_pwm0", "clk_counter_pwm0_src", 0, + RV1103B_PMUCLKGATE_CON(2), 5, GFLAGS), + GATE(SCLK_SPI2AHB, "sclk_spi2ahb", "sclk_spi2ahb_io", 0, + RV1103B_PMU1CLKGATE_CON(0), 2, GFLAGS), + GATE(CLK_UTMI_USBOTG, "clk_utmi_usbotg", "clk_utmi_usbotg_io", 0, + RV1103B_PERICRU_IP_CON, 14, GFLAGS), +}; + +static struct rockchip_clk_branch rv1103b_armclk __initdata = + MUX(ARMCLK, "armclk", mux_armclk_p, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + RV1103B_CORECLKSEL_CON(0), 1, 1, MFLAGS); + +static void __init rv1103b_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + unsigned long clk_nr; + void __iomem *reg_base; + + clk_nr = rockchip_clk_find_max_clk_id(rv1103b_clk_branches, + ARRAY_SIZE(rv1103b_clk_branches)) + 1; + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, clk_nr); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); + return; + } + + rockchip_clk_register_plls(ctx, rv1103b_pll_clks, + ARRAY_SIZE(rv1103b_pll_clks), + RV1103B_GRF_SOC_STATUS0); + + rockchip_clk_register_branches(ctx, rv1103b_clk_branches, + ARRAY_SIZE(rv1103b_clk_branches)); + + rockchip_clk_register_armclk_multi_pll(ctx, &rv1103b_armclk, + rv1103b_cpuclk_rates, + ARRAY_SIZE(rv1103b_cpuclk_rates)); + + rockchip_register_restart_notifier(ctx, RV1103B_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); + + /* pvtpll src init */ + writel_relaxed(PVTPLL_SRC_SEL_PVTPLL, reg_base + RV1103B_CORECLKSEL_CON(0)); + writel_relaxed(PVTPLL_SRC_SEL_PVTPLL, reg_base + RV1103B_NPUCLKSEL_CON(0)); + writel_relaxed(PVTPLL_SRC_SEL_PVTPLL, reg_base + RV1103B_VICLKSEL_CON(0)); + writel_relaxed(PVTPLL_SRC_SEL_PVTPLL, reg_base + RV1103B_VEPUCLKSEL_CON(0)); +} + +CLK_OF_DECLARE(rv1103b_cru, "rockchip,rv1103b-cru", rv1103b_clk_init); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index b2fff1d13a4a..cf0f5f11c34b 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -66,6 +66,55 @@ struct clk; #define PX30_PMU_CLKGATE_CON(x) ((x) * 0x4 + 0x80) #define PX30_PMU_MODE 0x0020 +#define RV1103B_TOPCRU_BASE 0x60000 +#define RV1103B_PERICRU_BASE 0x0 +#define RV1103B_VICRU_BASE 0x30000 +#define RV1103B_NPUCRU_BASE 0x20000 +#define RV1103B_CORECRU_BASE 0x40000 +#define RV1103B_VEPUCRU_BASE 0x10000 +#define RV1103B_DDRCRU_BASE 0x50000 +#define RV1103B_SUBDDRCRU_BASE 0x58000 +#define RV1103B_PMUCRU_BASE 0x70000 +#define RV1103B_PMU1CRU_BASE 0x80000 + +#define RV1103B_PMUCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_PMUCRU_BASE) +#define RV1103B_PMUCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_PMUCRU_BASE) +#define RV1103B_PMUSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_PMUCRU_BASE) +#define RV1103B_PMU1CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_PMU1CRU_BASE) +#define RV1103B_PMU1CLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_PMU1CRU_BASE) +#define RV1103B_PMU1SOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_PMU1CRU_BASE) +#define RV1103B_PLL_CON(x) ((x) * 0x4 + RV1103B_TOPCRU_BASE) +#define RV1103B_MODE_CON (0x280 + RV1103B_TOPCRU_BASE) +#define RV1103B_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_TOPCRU_BASE) +#define RV1103B_CLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_TOPCRU_BASE) +#define RV1103B_SOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_TOPCRU_BASE) +#define RV1103B_GLB_SRST_FST (0xc08 + RV1103B_TOPCRU_BASE) +#define RV1103B_GLB_SRST_SND (0xc0c + RV1103B_TOPCRU_BASE) +#define RV1103B_CLK_SAI_FRAC_DIV_HIGH (0xcc0 + RV1103B_TOPCRU_BASE) +#define RV1103B_PERICLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_PERICRU_BASE) +#define RV1103B_PERICLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_PERICRU_BASE) +#define RV1103B_PERISOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_PERICRU_BASE) +#define RV1103B_PERICRU_IP_CON (0xc08 + RV1103B_PERICRU_BASE) +#define RV1103B_VICLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_VICRU_BASE) +#define RV1103B_VICLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_VICRU_BASE) +#define RV1103B_VISOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_VICRU_BASE) +#define RV1103B_NPUCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_NPUCRU_BASE) +#define RV1103B_NPUCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_NPUCRU_BASE) +#define RV1103B_NPUSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_NPUCRU_BASE) +#define RV1103B_CORECLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_CORECRU_BASE) +#define RV1103B_CORECLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_CORECRU_BASE) +#define RV1103B_CORESOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_CORECRU_BASE) +#define RV1103B_VEPUCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_VEPUCRU_BASE) +#define RV1103B_VEPUCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_VEPUCRU_BASE) +#define RV1103B_VEPUSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_VEPUCRU_BASE) +#define RV1103B_DDRCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_DDRCRU_BASE) +#define RV1103B_DDRCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_DDRCRU_BASE) +#define RV1103B_DDRSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_DDRCRU_BASE) +#define RV1103B_SUBDDRCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1103B_SUBDDRCRU_BASE) +#define RV1103B_SUBDDRCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1103B_SUBDDRCRU_BASE) +#define RV1103B_SUBDDRSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1103B_SUBDDRCRU_BASE) +#define RV1103B_SUBDDRMODE_CON (0x280 + RV1103B_SUBDDRCRU_BASE) + #define RV1108_PLL_CON(x) ((x) * 0x4) #define RV1108_CLKSEL_CON(x) ((x) * 0x4 + 0x60) #define RV1108_CLKGATE_CON(x) ((x) * 0x4 + 0x120) From 51ac0f4b6d5f4965153d8c39644ecfb228480396 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 21 Jan 2026 13:04:15 -0500 Subject: [PATCH 04/19] dt-bindings: clock: imx6q[ul]-clock: add optional clock enet[1]_ref_pad Add optional clock source enet_ref_pad for imx6q, enet1_ref_pad for imx6ul, which input from ENET ref pad. Acked-by: Conor Dooley Signed-off-by: Frank Li Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260121-ccm_dts-v3-1-820ce9b5fa38@nxp.com Signed-off-by: Abel Vesa --- Documentation/devicetree/bindings/clock/imx6q-clock.yaml | 4 ++++ Documentation/devicetree/bindings/clock/imx6ul-clock.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.yaml b/Documentation/devicetree/bindings/clock/imx6q-clock.yaml index cd3c04c883df..0e6febe1c875 100644 --- a/Documentation/devicetree/bindings/clock/imx6q-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.yaml @@ -29,20 +29,24 @@ properties: const: 1 clocks: + minItems: 5 items: - description: 24m osc - description: 32k osc - description: ckih1 clock input - description: anaclk1 clock input - description: anaclk2 clock input + - description: clock input from enet ref pad clock-names: + minItems: 5 items: - const: osc - const: ckil - const: ckih1 - const: anaclk1 - const: anaclk2 + - const: enet_ref_pad fsl,pmic-stby-poweroff: $ref: /schemas/types.yaml#/definitions/flag diff --git a/Documentation/devicetree/bindings/clock/imx6ul-clock.yaml b/Documentation/devicetree/bindings/clock/imx6ul-clock.yaml index d57e18a210cc..035002721a3b 100644 --- a/Documentation/devicetree/bindings/clock/imx6ul-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx6ul-clock.yaml @@ -29,18 +29,22 @@ properties: const: 1 clocks: + minItems: 4 items: - description: 32k osc - description: 24m osc - description: ipp_di0 clock input - description: ipp_di1 clock input + - description: clock input from enet1 ref pad clock-names: + minItems: 4 items: - const: ckil - const: osc - const: ipp_di0 - const: ipp_di1 + - const: enet1_ref_pad required: - compatible From 1227a8f6c34e297b5fada96aa140129eced771dc Mon Sep 17 00:00:00 2001 From: Anirudh Srinivasan Date: Fri, 6 Mar 2026 11:12:17 -0600 Subject: [PATCH 05/19] dt-bindings: clk: tenstorrent: Add tenstorrent,atlantis-prcm-rcpu Document bindings for Tenstorrent Atlantis PRCM that manages clocks and resets. This block is instantiated multiple times in the SoC. This commit documents the clocks from the RCPU PRCM block. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Anirudh Srinivasan Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- .../clock/tenstorrent,atlantis-prcm-rcpu.yaml | 54 +++++++++ MAINTAINERS | 2 + .../clock/tenstorrent,atlantis-prcm-rcpu.h | 103 ++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml create mode 100644 include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h diff --git a/Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml b/Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml new file mode 100644 index 000000000000..7fa16526efce --- /dev/null +++ b/Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/tenstorrent,atlantis-prcm-rcpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tenstorrent Atlantis PRCM (Power, Reset, Clock Management) Module + +maintainers: + - Anirudh Srinivasan + +description: + Multifunctional register block found in Tenstorrent Atlantis SoC whose main + function is to control clocks and resets. This block is instantiated multiple + times in the SoC, each block controls clock and resets for a different + subsystem. RCPU prcm serves low speed IO interfaces. + +properties: + compatible: + enum: + - tenstorrent,atlantis-prcm-rcpu + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#clock-cells": + const: 1 + description: + See for valid indices. + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + clock-controller@a8000000 { + compatible = "tenstorrent,atlantis-prcm-rcpu"; + reg = <0xa8000000 0x10000>; + clocks = <&osc_24m>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 55af015174a5..40c179c8de1e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22809,8 +22809,10 @@ M: Joel Stanley L: linux-riscv@lists.infradead.org S: Maintained T: git https://github.com/tenstorrent/linux.git +F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml F: arch/riscv/boot/dts/tenstorrent/ +F: include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h RISC-V THEAD SoC SUPPORT M: Drew Fustini diff --git a/include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h b/include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h new file mode 100644 index 000000000000..c1c875e016f8 --- /dev/null +++ b/include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Tenstorrent Atlantis PRCM Clock and Reset Indices + * + * Copyright (c) 2026 Tenstorrent + */ + +#ifndef _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H +#define _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H + +/* + * RCPU Domain Clock IDs + */ +#define CLK_RCPU_PLL 0 +#define CLK_RCPU_ROOT 1 +#define CLK_RCPU_DIV2 2 +#define CLK_RCPU_DIV4 3 +#define CLK_RCPU_RTC 4 +#define CLK_SMNDMA0_ACLK 5 +#define CLK_SMNDMA1_ACLK 6 +#define CLK_WDT0_PCLK 7 +#define CLK_WDT1_PCLK 8 +#define CLK_TIMER_PCLK 9 +#define CLK_PVTC_PCLK 10 +#define CLK_PMU_PCLK 11 +#define CLK_MAILBOX_HCLK 12 +#define CLK_SEC_SPACC_HCLK 13 +#define CLK_SEC_OTP_HCLK 14 +#define CLK_TRNG_PCLK 15 +#define CLK_SEC_CRC_HCLK 16 +#define CLK_SMN_HCLK 17 +#define CLK_AHB0_HCLK 18 +#define CLK_SMN_PCLK 19 +#define CLK_SMN_CLK 20 +#define CLK_SCRATCHPAD_CLK 21 +#define CLK_RCPU_CORE_CLK 22 +#define CLK_RCPU_ROM_CLK 23 +#define CLK_OTP_LOAD_CLK 24 +#define CLK_NOC_PLL 25 +#define CLK_NOCC_CLK 26 +#define CLK_NOCC_DIV2 27 +#define CLK_NOCC_DIV4 28 +#define CLK_NOCC_RTC 29 +#define CLK_NOCC_CAN 30 +#define CLK_QSPI_SCLK 31 +#define CLK_QSPI_HCLK 32 +#define CLK_I2C0_PCLK 33 +#define CLK_I2C1_PCLK 34 +#define CLK_I2C2_PCLK 35 +#define CLK_I2C3_PCLK 36 +#define CLK_I2C4_PCLK 37 +#define CLK_UART0_PCLK 38 +#define CLK_UART1_PCLK 39 +#define CLK_UART2_PCLK 40 +#define CLK_UART3_PCLK 41 +#define CLK_UART4_PCLK 42 +#define CLK_SPI0_PCLK 43 +#define CLK_SPI1_PCLK 44 +#define CLK_SPI2_PCLK 45 +#define CLK_SPI3_PCLK 46 +#define CLK_GPIO_PCLK 47 +#define CLK_CAN0_HCLK 48 +#define CLK_CAN0_CLK 49 +#define CLK_CAN1_HCLK 50 +#define CLK_CAN1_CLK 51 +#define CLK_CAN0_TIMER_CLK 52 +#define CLK_CAN1_TIMER_CLK 53 + +/* RCPU domain reset */ +#define RST_SMNDMA0 0 +#define RST_SMNDMA1 1 +#define RST_WDT0 2 +#define RST_WDT1 3 +#define RST_TMR 4 +#define RST_PVTC 5 +#define RST_PMU 6 +#define RST_MAILBOX 7 +#define RST_SPACC 8 +#define RST_OTP 9 +#define RST_TRNG 10 +#define RST_CRC 11 +#define RST_QSPI 12 +#define RST_I2C0 13 +#define RST_I2C1 14 +#define RST_I2C2 15 +#define RST_I2C3 16 +#define RST_I2C4 17 +#define RST_UART0 18 +#define RST_UART1 19 +#define RST_UART2 20 +#define RST_UART3 21 +#define RST_UART4 22 +#define RST_SPI0 23 +#define RST_SPI1 24 +#define RST_SPI2 25 +#define RST_SPI3 26 +#define RST_GPIO 27 +#define RST_CAN0 28 +#define RST_CAN1 29 +#define RST_I2S0 30 +#define RST_I2S1 31 + +#endif /* _DT_BINDINGS_ATLANTIS_PRCM_RCPU_H */ From 89b23af16276a6d4d06064d72e3fd548de090375 Mon Sep 17 00:00:00 2001 From: Anirudh Srinivasan Date: Fri, 6 Mar 2026 11:12:18 -0600 Subject: [PATCH 06/19] reset: tenstorrent: Add reset controller for Atlantis Adds Atlantis Reset Controller driver, which shares the same regmap as prcm ( clock controller). This version of the reset controller driver covers resets from the RCPU prcm. Reviewed-by: Philipp Zabel Acked-by: Philipp Zabel Signed-off-by: Anirudh Srinivasan Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- MAINTAINERS | 1 + drivers/reset/Kconfig | 11 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-tenstorrent-atlantis.c | 173 +++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 drivers/reset/reset-tenstorrent-atlantis.c diff --git a/MAINTAINERS b/MAINTAINERS index 40c179c8de1e..493d007d3c65 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22812,6 +22812,7 @@ T: git https://github.com/tenstorrent/linux.git F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml F: arch/riscv/boot/dts/tenstorrent/ +F: drivers/reset/reset-tenstorrent-atlantis.c F: include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h RISC-V THEAD SoC SUPPORT diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 7ce151f6a7e4..85ee9da809ee 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -315,6 +315,17 @@ config RESET_SUNXI help This enables the reset driver for Allwinner SoCs. +config RESET_TENSTORRENT_ATLANTIS + tristate "Tenstorrent atlantis reset driver" + depends on ARCH_TENSTORRENT || COMPILE_TEST + select AUXILIARY_BUS + default ARCH_TENSTORRENT + help + This enables the driver for the reset controller + present in the Tenstorrent Atlantis SoC. + Enable this option to be able to use hardware + resets on Atalantis based systems. + config RESET_TH1520 tristate "T-HEAD TH1520 reset controller" depends on ARCH_THEAD || COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index fc0cc99f8514..7c086baeb02a 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o +obj-$(CONFIG_RESET_TENSTORRENT_ATLANTIS) += reset-tenstorrent-atlantis.o obj-$(CONFIG_RESET_TH1520) += reset-th1520.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o diff --git a/drivers/reset/reset-tenstorrent-atlantis.c b/drivers/reset/reset-tenstorrent-atlantis.c new file mode 100644 index 000000000000..ab8be52fdd5e --- /dev/null +++ b/drivers/reset/reset-tenstorrent-atlantis.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tenstorrent Atlantis PRCM Reset Driver + * + * Copyright (c) 2026 Tenstorrent + */ + +#include +#include +#include +#include + +/* RCPU Reset Register Offsets */ +#define RCPU_BLK_RST_REG 0x001c +#define LSIO_BLK_RST_REG 0x0020 +#define HSIO_BLK_RST_REG 0x000c +#define PCIE_SUBS_RST_REG 0x0000 +#define MM_RSTN_REG 0x0014 + +struct atlantis_reset_data { + u8 bit; + u16 reg; + bool active_low; +}; + +struct atlantis_reset_controller_data { + const struct atlantis_reset_data *reset_data; + size_t count; +}; + +struct atlantis_reset_controller { + struct reset_controller_dev rcdev; + const struct atlantis_reset_controller_data *data; + struct regmap *regmap; +}; + +static inline struct atlantis_reset_controller * +to_atlantis_reset_controller(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct atlantis_reset_controller, rcdev); +} + +#define RESET_DATA(_reg, _bit, _active_low) \ + { \ + .bit = _bit, .reg = _reg, .active_low = _active_low, \ + } + +static const struct atlantis_reset_data atlantis_rcpu_resets[] = { + [RST_SMNDMA0] = RESET_DATA(RCPU_BLK_RST_REG, 0, true), + [RST_SMNDMA1] = RESET_DATA(RCPU_BLK_RST_REG, 1, true), + [RST_WDT0] = RESET_DATA(RCPU_BLK_RST_REG, 2, true), + [RST_WDT1] = RESET_DATA(RCPU_BLK_RST_REG, 3, true), + [RST_TMR] = RESET_DATA(RCPU_BLK_RST_REG, 4, true), + [RST_PVTC] = RESET_DATA(RCPU_BLK_RST_REG, 12, true), + [RST_PMU] = RESET_DATA(RCPU_BLK_RST_REG, 13, true), + [RST_MAILBOX] = RESET_DATA(RCPU_BLK_RST_REG, 14, true), + [RST_SPACC] = RESET_DATA(RCPU_BLK_RST_REG, 26, true), + [RST_OTP] = RESET_DATA(RCPU_BLK_RST_REG, 28, true), + [RST_TRNG] = RESET_DATA(RCPU_BLK_RST_REG, 29, true), + [RST_CRC] = RESET_DATA(RCPU_BLK_RST_REG, 30, true), + [RST_QSPI] = RESET_DATA(LSIO_BLK_RST_REG, 0, true), + [RST_I2C0] = RESET_DATA(LSIO_BLK_RST_REG, 1, true), + [RST_I2C1] = RESET_DATA(LSIO_BLK_RST_REG, 2, true), + [RST_I2C2] = RESET_DATA(LSIO_BLK_RST_REG, 3, true), + [RST_I2C3] = RESET_DATA(LSIO_BLK_RST_REG, 4, true), + [RST_I2C4] = RESET_DATA(LSIO_BLK_RST_REG, 5, true), + [RST_UART0] = RESET_DATA(LSIO_BLK_RST_REG, 6, true), + [RST_UART1] = RESET_DATA(LSIO_BLK_RST_REG, 7, true), + [RST_UART2] = RESET_DATA(LSIO_BLK_RST_REG, 8, true), + [RST_UART3] = RESET_DATA(LSIO_BLK_RST_REG, 9, true), + [RST_UART4] = RESET_DATA(LSIO_BLK_RST_REG, 10, true), + [RST_SPI0] = RESET_DATA(LSIO_BLK_RST_REG, 11, true), + [RST_SPI1] = RESET_DATA(LSIO_BLK_RST_REG, 12, true), + [RST_SPI2] = RESET_DATA(LSIO_BLK_RST_REG, 13, true), + [RST_SPI3] = RESET_DATA(LSIO_BLK_RST_REG, 14, true), + [RST_GPIO] = RESET_DATA(LSIO_BLK_RST_REG, 15, true), + [RST_CAN0] = RESET_DATA(LSIO_BLK_RST_REG, 17, true), + [RST_CAN1] = RESET_DATA(LSIO_BLK_RST_REG, 18, true), + [RST_I2S0] = RESET_DATA(LSIO_BLK_RST_REG, 19, true), + [RST_I2S1] = RESET_DATA(LSIO_BLK_RST_REG, 20, true), + +}; + +static const struct atlantis_reset_controller_data atlantis_rcpu_reset_data = { + .reset_data = atlantis_rcpu_resets, + .count = ARRAY_SIZE(atlantis_rcpu_resets), +}; + +static int atlantis_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + unsigned int val; + struct atlantis_reset_controller *rst = + to_atlantis_reset_controller(rcdev); + const struct atlantis_reset_data *data = &rst->data->reset_data[id]; + unsigned int mask = BIT(data->bit); + struct regmap *regmap = rst->regmap; + + if (data->active_low ^ assert) + val = mask; + else + val = 0; + + return regmap_update_bits(regmap, data->reg, mask, val); +} + +static int atlantis_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return atlantis_reset_update(rcdev, id, true); +} + +static int atlantis_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return atlantis_reset_update(rcdev, id, false); +} + +static const struct reset_control_ops atlantis_reset_control_ops = { + .assert = atlantis_reset_assert, + .deassert = atlantis_reset_deassert, +}; + +static int +atlantis_reset_controller_register(struct device *dev, + struct atlantis_reset_controller *controller) +{ + struct reset_controller_dev *rcdev = &controller->rcdev; + + rcdev->ops = &atlantis_reset_control_ops; + rcdev->owner = THIS_MODULE; + rcdev->of_node = dev->of_node; + rcdev->nr_resets = controller->data->count; + + return devm_reset_controller_register(dev, &controller->rcdev); +} +static int atlantis_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct atlantis_reset_controller *controller; + struct device *dev = &adev->dev; + struct regmap *regmap; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENODEV; + + controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); + if (!controller) + return -ENOMEM; + controller->data = + (const struct atlantis_reset_controller_data *)id->driver_data; + controller->regmap = regmap; + + return atlantis_reset_controller_register(dev, controller); +} + +static const struct auxiliary_device_id atlantis_reset_ids[] = { + { .name = "atlantis_prcm.rcpu-reset", + .driver_data = (kernel_ulong_t)&atlantis_rcpu_reset_data }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, atlantis_reset_ids); + +static struct auxiliary_driver atlantis_reset_driver = { + .probe = atlantis_reset_probe, + .id_table = atlantis_reset_ids, +}; +module_auxiliary_driver(atlantis_reset_driver); + +MODULE_AUTHOR("Anirudh Srinivasan "); +MODULE_DESCRIPTION("Atlantis PRCM reset controller driver"); +MODULE_LICENSE("GPL"); From 23c8ebc952849b3ba47d04d0ec95daf5cc136061 Mon Sep 17 00:00:00 2001 From: Anirudh Srinivasan Date: Fri, 6 Mar 2026 11:12:19 -0600 Subject: [PATCH 07/19] clk: tenstorrent: Add Atlantis clock controller driver Add driver for clock controller in Tenstorrent Atlantis SoC. This version of the driver covers clocks from RCPU subsystem. 5 types of clocks generated by this controller: PLLs (PLLs with bypass functionality and an additional Gate clk at output), Shared Gates (Multiple Gate clks that share an enable bit), standard Muxes, Dividers and Gates. All clocks are implemented using custom clk ops and use the regmap interface associated with the syscon. All clocks are derived from a 24 Mhz oscillator. The reset controller is also setup as an auxiliary device of the clock controller. Signed-off-by: Anirudh Srinivasan Reviewed-by: Brian Masney Reviewed-by: Drew Fustini Signed-off-by: Drew Fustini --- MAINTAINERS | 1 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/tenstorrent/Kconfig | 14 + drivers/clk/tenstorrent/Makefile | 3 + drivers/clk/tenstorrent/atlantis-prcm.c | 870 ++++++++++++++++++++++++ 6 files changed, 890 insertions(+) create mode 100644 drivers/clk/tenstorrent/Kconfig create mode 100644 drivers/clk/tenstorrent/Makefile create mode 100644 drivers/clk/tenstorrent/atlantis-prcm.c diff --git a/MAINTAINERS b/MAINTAINERS index 493d007d3c65..a7783eb0a7de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22812,6 +22812,7 @@ T: git https://github.com/tenstorrent/linux.git F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml F: arch/riscv/boot/dts/tenstorrent/ +F: drivers/clk/tenstorrent/ F: drivers/reset/reset-tenstorrent-atlantis.c F: include/dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3d803b4cf5c1..8cc300b90b5f 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -531,6 +531,7 @@ source "drivers/clk/starfive/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" +source "drivers/clk/tenstorrent/Kconfig" source "drivers/clk/thead/Kconfig" source "drivers/clk/stm32/Kconfig" source "drivers/clk/ti/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f7bce3951a30..f52cf3ac64fc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -155,6 +155,7 @@ obj-y += starfive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-y += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-y += tenstorrent/ obj-$(CONFIG_ARCH_THEAD) += thead/ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ diff --git a/drivers/clk/tenstorrent/Kconfig b/drivers/clk/tenstorrent/Kconfig new file mode 100644 index 000000000000..9d4391eeeae0 --- /dev/null +++ b/drivers/clk/tenstorrent/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config TENSTORRENT_ATLANTIS_PRCM + tristate "Support for Tenstorrent Atlantis PRCM Clock Controller" + depends on ARCH_TENSTORRENT || COMPILE_TEST + default ARCH_TENSTORRENT + select REGMAP_MMIO + select AUXILIARY_BUS + select MFD_SYSCON + help + Say yes here to support the different clock + controllers found in the Tenstorrent Atlantis SoC. + This includes the clocks from the RCPU, HSIO, MMIO + and PCIE domain. diff --git a/drivers/clk/tenstorrent/Makefile b/drivers/clk/tenstorrent/Makefile new file mode 100644 index 000000000000..95d87bac7bf5 --- /dev/null +++ b/drivers/clk/tenstorrent/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_TENSTORRENT_ATLANTIS_PRCM) += atlantis-prcm.o diff --git a/drivers/clk/tenstorrent/atlantis-prcm.c b/drivers/clk/tenstorrent/atlantis-prcm.c new file mode 100644 index 000000000000..6d4386eeb7da --- /dev/null +++ b/drivers/clk/tenstorrent/atlantis-prcm.c @@ -0,0 +1,870 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Tenstorrent Atlantis PRCM Clock Driver + * + * Copyright (c) 2026 Tenstorrent + */ + +#include +#include +#include +#include +#include +#include +#include + +/* RCPU Clock Register Offsets */ +#define PLL_RCPU_CFG_REG 0x0000 +#define PLL_NOCC_CFG_REG 0x0004 +#define NOCC_CLK_CFG_REG 0x0008 +#define RCPU_DIV_CFG_REG 0x000C +#define RCPU_BLK_CG_REG 0x0014 +#define LSIO_BLK_CG_REG 0x0018 +#define PLL_RCPU_EN_REG 0x011C +#define PLL_NOCC_EN_REG 0x0120 +#define BUS_CG_REG 0x01FC + +/* PLL Bit Definitions */ +#define PLL_CFG_EN_BIT BIT(0) +#define PLL_CFG_BYPASS_BIT BIT(1) +#define PLL_CFG_REFDIV_MASK GENMASK(7, 2) +#define PLL_CFG_REFDIV_SHIFT 2 +#define PLL_CFG_POSTDIV1_MASK GENMASK(10, 8) +#define PLL_CFG_POSTDIV1_SHIFT 8 +#define PLL_CFG_POSTDIV2_MASK GENMASK(13, 11) +#define PLL_CFG_POSTDIV2_SHIFT 11 +#define PLL_CFG_FBDIV_MASK GENMASK(25, 14) +#define PLL_CFG_FBDIV_SHIFT 14 +#define PLL_CFG_LKDT_BIT BIT(30) +#define PLL_CFG_LOCK_BIT BIT(31) +#define PLL_LOCK_TIMEOUT_US 1000 +#define PLL_BYPASS_WAIT_US 500 + +struct atlantis_clk_common { + int clkid; + struct regmap *regmap; + struct clk_hw hw; +}; + +static inline struct atlantis_clk_common * +hw_to_atlantis_clk_common(struct clk_hw *hw) +{ + return container_of(hw, struct atlantis_clk_common, hw); +} + +struct atlantis_clk_mux_config { + u8 shift; + u8 width; + u32 reg_offset; +}; + +struct atlantis_clk_mux { + struct atlantis_clk_common common; + struct atlantis_clk_mux_config config; +}; + +struct atlantis_clk_gate_config { + u32 reg_offset; + u32 enable; +}; + +struct atlantis_clk_gate { + struct atlantis_clk_common common; + struct atlantis_clk_gate_config config; +}; + +struct atlantis_clk_divider_config { + u8 shift; + u8 width; + u32 flags; + u32 reg_offset; +}; + +struct atlantis_clk_divider { + struct atlantis_clk_common common; + struct atlantis_clk_divider_config config; +}; + +struct atlantis_clk_pll_config { + u32 tbl_num; + u32 reg_offset; + u32 en_reg_offset; + u32 cg_reg_offset; + u32 cg_reg_enable; +}; + +/* Models a PLL with Bypass Functionality and Enable Bit + an optional Gate Clock at it's output */ +struct atlantis_clk_pll { + struct atlantis_clk_common common; + struct atlantis_clk_pll_config config; +}; + +struct atlantis_clk_gate_shared_config { + u32 reg_offset; + u32 enable; + unsigned int *share_count; + spinlock_t *refcount_lock; +}; + +struct atlantis_clk_gate_shared { + struct atlantis_clk_common common; + struct atlantis_clk_gate_shared_config config; +}; + +struct atlantis_clk_fixed_factor_config { + unsigned int mult; + unsigned int div; +}; + +struct atlantis_clk_fixed_factor { + struct atlantis_clk_fixed_factor_config config; + struct atlantis_clk_common common; +}; + +static inline struct atlantis_clk_mux *hw_to_atlantis_clk_mux(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_mux, common); +} + +static inline struct atlantis_clk_gate * +hw_to_atlantis_clk_gate(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_gate, common); +} + +static inline struct atlantis_clk_divider * +hw_to_atlantis_clk_divider(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_divider, common); +} + +static inline struct atlantis_clk_pll *hw_to_atlantis_pll(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_pll, common); +} + +static inline struct atlantis_clk_gate_shared * +hw_to_atlantis_clk_gate_shared(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_gate_shared, common); +} + +static inline struct atlantis_clk_fixed_factor * +hw_to_atlantis_clk_fixed_factor(struct clk_hw *hw) +{ + struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw); + + return container_of(common, struct atlantis_clk_fixed_factor, common); +} + +static u8 atlantis_clk_mux_get_parent(struct clk_hw *hw) +{ + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); + u32 val; + + regmap_read(mux->common.regmap, mux->config.reg_offset, &val); + val >>= mux->config.shift; + val &= (BIT(mux->config.width) - 1); + + return val; +} + +static int atlantis_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw); + u32 val = index; + + return regmap_update_bits(mux->common.regmap, mux->config.reg_offset, + (BIT(mux->config.width) - 1) << mux->config.shift, + val << mux->config.shift); +} + +static int atlantis_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return clk_mux_determine_rate_flags(hw, req, hw->init->flags); +} + +static const struct clk_ops atlantis_clk_mux_ops = { + .get_parent = atlantis_clk_mux_get_parent, + .set_parent = atlantis_clk_mux_set_parent, + .determine_rate = atlantis_clk_mux_determine_rate, +}; + +static int atlantis_clk_gate_endisable(struct clk_hw *hw, int enable) +{ + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); + + if (enable) + return regmap_set_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable); + else + return regmap_clear_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable); +} + +static int atlantis_clk_gate_enable(struct clk_hw *hw) +{ + return atlantis_clk_gate_endisable(hw, 1); +} + +static void atlantis_clk_gate_disable(struct clk_hw *hw) +{ + atlantis_clk_gate_endisable(hw, 0); +} + +static int atlantis_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); + + return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); +} + +static const struct clk_ops atlantis_clk_gate_ops = { + .enable = atlantis_clk_gate_enable, + .disable = atlantis_clk_gate_disable, + .is_enabled = atlantis_clk_gate_is_enabled, +}; + +static unsigned long atlantis_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct atlantis_clk_divider *divider = hw_to_atlantis_clk_divider(hw); + u32 val; + + regmap_read(divider->common.regmap, divider->config.reg_offset, &val); + + val >>= divider->config.shift; + val &= ((1 << (divider->config.width)) - 1); + + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); +} + +static const struct clk_ops atlantis_clk_divider_ops = { + .recalc_rate = atlantis_clk_divider_recalc_rate, +}; + +static unsigned long +atlantis_clk_fixed_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct atlantis_clk_fixed_factor *factor = + hw_to_atlantis_clk_fixed_factor(hw); + unsigned long long rate; + + rate = (unsigned long long)parent_rate * factor->config.mult; + do_div(rate, factor->config.div); + + return (unsigned long)rate; +} + +static const struct clk_ops atlantis_clk_fixed_factor_ops = { + .recalc_rate = atlantis_clk_fixed_factor_recalc_rate, +}; + +static int atlantis_clk_pll_is_enabled(struct clk_hw *hw) +{ + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); + u32 val, en_val, cg_val; + + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); + + /* Check if PLL is powered on, locked, not bypassed and Gate clk is enabled */ + return !!(en_val & PLL_CFG_EN_BIT) && !!(val & PLL_CFG_LOCK_BIT) && + (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && + !(val & PLL_CFG_BYPASS_BIT); +} + +static int atlantis_clk_pll_enable(struct clk_hw *hw) +{ + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); + u32 val, en_val, cg_val; + int ret; + + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); + regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val); + regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val); + + /* Check if PLL is already enabled, locked, not bypassed and Gate clk is enabled */ + if ((en_val & PLL_CFG_EN_BIT) && (val & PLL_CFG_LOCK_BIT) && + (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) && + !(val & PLL_CFG_BYPASS_BIT)) { + return 0; + } + + /* Step 1: Set bypass mode first */ + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); + + /* Step 2: Enable PLL (clear then set power bit) */ + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, + PLL_CFG_EN_BIT, 0); + + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, + PLL_CFG_EN_BIT, PLL_CFG_EN_BIT); + + /* Step 3: Wait for PLL lock */ + ret = regmap_read_poll_timeout(pll->common.regmap, + pll->config.reg_offset, val, + val & PLL_CFG_LOCK_BIT, + PLL_BYPASS_WAIT_US, PLL_LOCK_TIMEOUT_US); + if (ret) { + pr_err("PLL failed to lock within timeout\n"); + return ret; + } + + /* Step 4: Switch from bypass to PLL output */ + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, + PLL_CFG_BYPASS_BIT, 0); + + /* Enable Gate clk at PLL Output */ + return regmap_update_bits(pll->common.regmap, pll->config.cg_reg_offset, + pll->config.cg_reg_enable, + pll->config.cg_reg_enable); +} + +static void atlantis_clk_pll_disable(struct clk_hw *hw) +{ + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); + + /* Step 1: Switch to bypass mode before disabling */ + regmap_update_bits(pll->common.regmap, pll->config.reg_offset, + PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT); + /* Step 2: Power down PLL */ + regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset, + PLL_CFG_EN_BIT, 0); +} + +static unsigned long atlantis_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw); + + u32 val, refdiv, fbdiv, postdiv1, postdiv2; + u64 fout; + + regmap_read(pll->common.regmap, pll->config.reg_offset, &val); + + if (val & PLL_CFG_BYPASS_BIT) + return parent_rate; + + refdiv = FIELD_GET(PLL_CFG_REFDIV_MASK, val); + fbdiv = FIELD_GET(PLL_CFG_FBDIV_MASK, val); + postdiv1 = FIELD_GET(PLL_CFG_POSTDIV1_MASK, val); + postdiv2 = FIELD_GET(PLL_CFG_POSTDIV2_MASK, val); + + if (!refdiv) + refdiv = 1; + if (!postdiv1) + postdiv1 = 1; + if (!postdiv2) + postdiv2 = 1; + if (!fbdiv) + return 0; + + fout = div64_u64((u64)parent_rate * fbdiv, + refdiv * postdiv1 * postdiv2); + + return fout; +} + +static const struct clk_ops atlantis_clk_pll_ops = { + .enable = atlantis_clk_pll_enable, + .disable = atlantis_clk_pll_disable, + .recalc_rate = atlantis_clk_pll_recalc_rate, + .is_enabled = atlantis_clk_pll_is_enabled, +}; + +static int atlantis_clk_gate_shared_enable(struct clk_hw *hw) +{ + struct atlantis_clk_gate_shared *gate = + hw_to_atlantis_clk_gate_shared(hw); + bool need_enable; + + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) + { + need_enable = (*gate->config.share_count)++ == 0; + if (need_enable) { + regmap_set_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable); + } + } + + if (need_enable) { + if (!regmap_test_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable)) { + pr_warn("%s: gate enable %d failed to enable\n", + clk_hw_get_name(hw), gate->config.enable); + return -EIO; + } + } + + return 0; +} + +static void atlantis_clk_gate_shared_disable(struct clk_hw *hw) +{ + struct atlantis_clk_gate_shared *gate = + hw_to_atlantis_clk_gate_shared(hw); + + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) + { + if (WARN_ON(*gate->config.share_count == 0)) + return; + if (--(*gate->config.share_count) > 0) + return; + + regmap_clear_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable); + } +} + +static int atlantis_clk_gate_shared_is_enabled(struct clk_hw *hw) +{ + struct atlantis_clk_gate_shared *gate = + hw_to_atlantis_clk_gate_shared(hw); + + return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); +} + +static void atlantis_clk_gate_shared_disable_unused(struct clk_hw *hw) +{ + struct atlantis_clk_gate_shared *gate = + hw_to_atlantis_clk_gate_shared(hw); + + scoped_guard(spinlock_irqsave, gate->config.refcount_lock) + { + if (*gate->config.share_count == 0) + regmap_clear_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable); + } +} + +static const struct clk_ops atlantis_clk_gate_shared_ops = { + .enable = atlantis_clk_gate_shared_enable, + .disable = atlantis_clk_gate_shared_disable, + .disable_unused = atlantis_clk_gate_shared_disable_unused, + .is_enabled = atlantis_clk_gate_shared_is_enabled, +}; + +#define ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, _cg_reg_offset, \ + _cg_reg_enable) \ + { \ + .reg_offset = (_reg_offset), \ + .en_reg_offset = (_en_reg_offset), \ + .cg_reg_offset = (_cg_reg_offset), \ + .cg_reg_enable = (_cg_reg_enable), \ + } + +#define ATLANTIS_PLL_DEFINE(_clkid, _name, _parent, _reg_offset, \ + _en_reg_offset, _cg_reg_offset, _cg_reg_enable, \ + _flags) \ + static struct atlantis_clk_pll _name = { \ + .config = ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, \ + _cg_reg_offset, _cg_reg_enable), \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ + #_name, _parent, &atlantis_clk_pll_ops, \ + _flags) }, \ + } +#define ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset) \ + { \ + .shift = _shift, .width = _width, .reg_offset = _reg_offset \ + } + +#define ATLANTIS_MUX_DEFINE(_clkid, _name, _parents, _reg_offset, _shift, \ + _width, _flags) \ + static struct atlantis_clk_mux _name = { \ + .config = ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset), \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA( \ + #_name, _parents, &atlantis_clk_mux_ops, \ + _flags) } \ + } + +#define ATLANTIS_DIVIDER_CONFIG(_shift, _width, _flags, _reg_offset) \ + { \ + .shift = _shift, .width = _width, .flags = _flags, \ + .reg_offset = _reg_offset \ + } + +#define ATLANTIS_DIVIDER_DEFINE(_clkid, _name, _parent, _reg_offset, _shift, \ + _width, _divflags, _flags) \ + static struct atlantis_clk_divider _name = { \ + .config = ATLANTIS_DIVIDER_CONFIG(_shift, _width, _divflags, \ + _reg_offset), \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_HW( \ + #_name, &_parent.common.hw, \ + &atlantis_clk_divider_ops, _flags) } \ + } +#define ATLANTIS_GATE_CONFIG(_enable, _reg_offset) \ + { \ + .enable = _enable, .reg_offset = _reg_offset \ + } + +#define ATLANTIS_GATE_DEFINE(_clkid, _name, _parent, _reg_offset, _enable, \ + _flags) \ + static struct atlantis_clk_gate _name = { \ + .config = ATLANTIS_GATE_CONFIG(_enable, _reg_offset), \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_HW( \ + #_name, &_parent.common.hw, \ + &atlantis_clk_gate_ops, _flags) } \ + } +#define ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, _share_count) \ + { \ + .reg_offset = _reg_offset, .enable = _enable, \ + .share_count = _share_count, .refcount_lock = &refcount_lock \ + } +#define ATLANTIS_GATE_SHARED_DEFINE(_clkid, _name, _parent, _reg_offset, \ + _enable, _share_count, _flags) \ + static struct atlantis_clk_gate_shared _name = { \ + .config = ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, \ + _share_count), \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_HW( \ + #_name, &_parent.common.hw, \ + &atlantis_clk_gate_shared_ops, _flags) } \ + } +#define ATLANTIS_FIXED_FACTOR_DEFINE(_clkid, _name, _parent, _mult, _div, \ + _flags) \ + static struct atlantis_clk_fixed_factor _name = { \ + .config = { .mult = _mult, .div = _div }, \ + .common = { .clkid = _clkid, \ + .hw.init = CLK_HW_INIT_HW( \ + #_name, &_parent.common.hw, \ + &atlantis_clk_fixed_factor_ops, _flags) } \ + } + +static DEFINE_SPINLOCK(refcount_lock); /* Lock for refcount value accesses */ + +static const struct regmap_config atlantis_prcm_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xFFFC, + .cache_type = REGCACHE_NONE, +}; + +struct atlantis_prcm_data { + struct clk_hw **hws; + size_t num; + const char *reset_name; +}; + +static const struct clk_parent_data osc_24m_clk[] = { + { .index = 0 }, +}; + +ATLANTIS_PLL_DEFINE(CLK_RCPU_PLL, rcpu_pll_clk, osc_24m_clk, PLL_RCPU_CFG_REG, + PLL_RCPU_EN_REG, BUS_CG_REG, 0, /* No Gate Clk at Output */ + CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); + +static const struct clk_parent_data rcpu_root_parents[] = { + { .index = 0 }, + { .hw = &rcpu_pll_clk.common.hw }, +}; + +ATLANTIS_MUX_DEFINE(CLK_RCPU_ROOT, rcpu_root_clk, rcpu_root_parents, + RCPU_DIV_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT); + +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV2, rcpu_div2_clk, rcpu_root_clk, + RCPU_DIV_CFG_REG, 2, 4, 0, 0); +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV4, rcpu_div4_clk, rcpu_root_clk, + RCPU_DIV_CFG_REG, 7, 4, 0, 0); +ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_RTC, rcpu_rtc_clk, rcpu_div4_clk, + RCPU_DIV_CFG_REG, 12, 6, 0, 0); + +ATLANTIS_GATE_DEFINE(CLK_SMNDMA0_ACLK, rcpu_dma0_clk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(0), 0); +ATLANTIS_GATE_DEFINE(CLK_SMNDMA1_ACLK, rcpu_dma1_clk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(1), 0); +ATLANTIS_GATE_DEFINE(CLK_WDT0_PCLK, sl_wdt0_pclk, rcpu_div4_clk, + RCPU_BLK_CG_REG, BIT(2), 0); +ATLANTIS_GATE_DEFINE(CLK_WDT1_PCLK, sl_wdt1_pclk, rcpu_div4_clk, + RCPU_BLK_CG_REG, BIT(3), 0); +ATLANTIS_GATE_DEFINE(CLK_TIMER_PCLK, sl_timer_pclk, rcpu_div4_clk, + RCPU_BLK_CG_REG, BIT(4), 0); +ATLANTIS_GATE_DEFINE(CLK_PVTC_PCLK, sl_pvtc_pclk, rcpu_div4_clk, + RCPU_BLK_CG_REG, BIT(12), 0); +ATLANTIS_GATE_DEFINE(CLK_PMU_PCLK, sl_pmu_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG, + BIT(13), 0); +ATLANTIS_GATE_DEFINE(CLK_MAILBOX_HCLK, rcpu_ipc_clk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(14), 0); +ATLANTIS_GATE_DEFINE(CLK_SEC_SPACC_HCLK, sec_spacc_hclk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(26), 0); +ATLANTIS_GATE_DEFINE(CLK_SEC_OTP_HCLK, sec_otp_hclk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(28), 0); +ATLANTIS_GATE_DEFINE(CLK_TRNG_PCLK, sec_trng_pclk, rcpu_div4_clk, + RCPU_BLK_CG_REG, BIT(29), 0); +ATLANTIS_GATE_DEFINE(CLK_SEC_CRC_HCLK, sec_crc_hclk, rcpu_div2_clk, + RCPU_BLK_CG_REG, BIT(30), 0); + +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_HCLK, rcpu_smn_hclk, rcpu_div2_clk, 1, 1, + 0); +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_AHB0_HCLK, rcpu_ahb0_hclk, rcpu_div2_clk, 1, 1, + 0); + +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_PCLK, rcpu_smn_pclk, rcpu_div4_clk, 1, 1, + 0); + +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_CLK, rcpu_smn_clk, rcpu_root_clk, 1, 1, 0); +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SCRATCHPAD_CLK, rcpu_scratchpad_aclk, + rcpu_root_clk, 1, 1, 0); +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_CORE_CLK, rcpu_core_clk, rcpu_root_clk, 1, + 1, 0); +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_ROM_CLK, rcpu_rom_aclk, rcpu_root_clk, 1, + 1, 0); + +static struct atlantis_clk_fixed_factor + otp_load_clk = { .config = { .mult = 1, .div = 1 }, + .common = { + .clkid = CLK_OTP_LOAD_CLK, + .hw.init = CLK_HW_INIT_PARENTS_DATA( + "otp_load_clk", osc_24m_clk, + &atlantis_clk_fixed_factor_ops, + CLK_SET_RATE_NO_REPARENT), + } }; + +ATLANTIS_PLL_DEFINE(CLK_NOC_PLL, nocc_pll_clk, osc_24m_clk, PLL_NOCC_CFG_REG, + PLL_NOCC_EN_REG, BUS_CG_REG, BIT(0), + CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL); + +static const struct clk_parent_data nocc_mux_parents[] = { + { .index = 0 }, + { .hw = &nocc_pll_clk.common.hw }, +}; + +ATLANTIS_MUX_DEFINE(CLK_NOCC_CLK, nocc_clk, nocc_mux_parents, NOCC_CLK_CFG_REG, + 0, 1, CLK_SET_RATE_NO_REPARENT); + +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV2, nocc_div2_clk, nocc_clk, + NOCC_CLK_CFG_REG, 1, 4, 0, 0); +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV4, nocc_div4_clk, nocc_clk, + NOCC_CLK_CFG_REG, 5, 4, 0, 0); +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_RTC, nocc_rtc_clk, nocc_div4_clk, + NOCC_CLK_CFG_REG, 9, 6, 0, 0); +ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_CAN, nocc_can_clk, nocc_clk, NOCC_CLK_CFG_REG, + 15, 4, 0, 0); + +static unsigned int refcnt_qspi; +ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_SCLK, lsio_qspi_sclk, nocc_clk, + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); +ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_HCLK, lsio_qspi_hclk, nocc_div2_clk, + LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0); +ATLANTIS_GATE_DEFINE(CLK_I2C0_PCLK, lsio_i2c0_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(1), 0); +ATLANTIS_GATE_DEFINE(CLK_I2C1_PCLK, lsio_i2c1_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(2), 0); +ATLANTIS_GATE_DEFINE(CLK_I2C2_PCLK, lsio_i2c2_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(3), 0); +ATLANTIS_GATE_DEFINE(CLK_I2C3_PCLK, lsio_i2c3_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(4), 0); +ATLANTIS_GATE_DEFINE(CLK_I2C4_PCLK, lsio_i2c4_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(5), 0); + +ATLANTIS_GATE_DEFINE(CLK_UART0_PCLK, lsio_uart0_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(6), 0); +ATLANTIS_GATE_DEFINE(CLK_UART1_PCLK, lsio_uart1_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(7), 0); +ATLANTIS_GATE_DEFINE(CLK_UART2_PCLK, lsio_uart2_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(8), 0); +ATLANTIS_GATE_DEFINE(CLK_UART3_PCLK, lsio_uart3_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(9), 0); +ATLANTIS_GATE_DEFINE(CLK_UART4_PCLK, lsio_uart4_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(10), 0); +ATLANTIS_GATE_DEFINE(CLK_SPI0_PCLK, lsio_spi0_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(11), 0); +ATLANTIS_GATE_DEFINE(CLK_SPI1_PCLK, lsio_spi1_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(12), 0); +ATLANTIS_GATE_DEFINE(CLK_SPI2_PCLK, lsio_spi2_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(13), 0); +ATLANTIS_GATE_DEFINE(CLK_SPI3_PCLK, lsio_spi3_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(14), 0); +ATLANTIS_GATE_DEFINE(CLK_GPIO_PCLK, lsio_gpio_pclk, nocc_div4_clk, + LSIO_BLK_CG_REG, BIT(15), 0); + +static unsigned int refcnt_can0; +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_HCLK, lsio_can0_hclk, nocc_div2_clk, + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_CLK, lsio_can0_clk, nocc_can_clk, + LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0); + +static unsigned int refcnt_can1; +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_HCLK, lsio_can1_hclk, nocc_div2_clk, + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); +ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_CLK, lsio_can1_clk, nocc_can_clk, + LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0); + +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN0_TIMER_CLK, lsio_can0_timer_clk, + nocc_rtc_clk, 1, 1, 0); +ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN1_TIMER_CLK, lsio_can1_timer_clk, + nocc_rtc_clk, 1, 1, 0); + +static struct clk_hw *atlantis_rcpu_clks[] = { + [CLK_RCPU_PLL] = &rcpu_pll_clk.common.hw, + [CLK_RCPU_ROOT] = &rcpu_root_clk.common.hw, + [CLK_RCPU_DIV2] = &rcpu_div2_clk.common.hw, + [CLK_RCPU_DIV4] = &rcpu_div4_clk.common.hw, + [CLK_RCPU_RTC] = &rcpu_rtc_clk.common.hw, + [CLK_SMNDMA0_ACLK] = &rcpu_dma0_clk.common.hw, + [CLK_SMNDMA1_ACLK] = &rcpu_dma1_clk.common.hw, + [CLK_WDT0_PCLK] = &sl_wdt0_pclk.common.hw, + [CLK_WDT1_PCLK] = &sl_wdt1_pclk.common.hw, + [CLK_TIMER_PCLK] = &sl_timer_pclk.common.hw, + [CLK_PVTC_PCLK] = &sl_pvtc_pclk.common.hw, + [CLK_PMU_PCLK] = &sl_pmu_pclk.common.hw, + [CLK_MAILBOX_HCLK] = &rcpu_ipc_clk.common.hw, + [CLK_SEC_SPACC_HCLK] = &sec_spacc_hclk.common.hw, + [CLK_SEC_OTP_HCLK] = &sec_otp_hclk.common.hw, + [CLK_TRNG_PCLK] = &sec_trng_pclk.common.hw, + [CLK_SEC_CRC_HCLK] = &sec_crc_hclk.common.hw, + [CLK_SMN_HCLK] = &rcpu_smn_hclk.common.hw, + [CLK_AHB0_HCLK] = &rcpu_ahb0_hclk.common.hw, + [CLK_SMN_PCLK] = &rcpu_smn_pclk.common.hw, + [CLK_SMN_CLK] = &rcpu_smn_clk.common.hw, + [CLK_SCRATCHPAD_CLK] = &rcpu_scratchpad_aclk.common.hw, + [CLK_RCPU_CORE_CLK] = &rcpu_core_clk.common.hw, + [CLK_RCPU_ROM_CLK] = &rcpu_rom_aclk.common.hw, + [CLK_OTP_LOAD_CLK] = &otp_load_clk.common.hw, + [CLK_NOC_PLL] = &nocc_pll_clk.common.hw, + [CLK_NOCC_CLK] = &nocc_clk.common.hw, + [CLK_NOCC_DIV2] = &nocc_div2_clk.common.hw, + [CLK_NOCC_DIV4] = &nocc_div4_clk.common.hw, + [CLK_NOCC_RTC] = &nocc_rtc_clk.common.hw, + [CLK_NOCC_CAN] = &nocc_can_clk.common.hw, + [CLK_QSPI_SCLK] = &lsio_qspi_sclk.common.hw, + [CLK_QSPI_HCLK] = &lsio_qspi_hclk.common.hw, + [CLK_I2C0_PCLK] = &lsio_i2c0_pclk.common.hw, + [CLK_I2C1_PCLK] = &lsio_i2c1_pclk.common.hw, + [CLK_I2C2_PCLK] = &lsio_i2c2_pclk.common.hw, + [CLK_I2C3_PCLK] = &lsio_i2c3_pclk.common.hw, + [CLK_I2C4_PCLK] = &lsio_i2c4_pclk.common.hw, + [CLK_UART0_PCLK] = &lsio_uart0_pclk.common.hw, + [CLK_UART1_PCLK] = &lsio_uart1_pclk.common.hw, + [CLK_UART2_PCLK] = &lsio_uart2_pclk.common.hw, + [CLK_UART3_PCLK] = &lsio_uart3_pclk.common.hw, + [CLK_UART4_PCLK] = &lsio_uart4_pclk.common.hw, + [CLK_SPI0_PCLK] = &lsio_spi0_pclk.common.hw, + [CLK_SPI1_PCLK] = &lsio_spi1_pclk.common.hw, + [CLK_SPI2_PCLK] = &lsio_spi2_pclk.common.hw, + [CLK_SPI3_PCLK] = &lsio_spi3_pclk.common.hw, + [CLK_GPIO_PCLK] = &lsio_gpio_pclk.common.hw, + [CLK_CAN0_HCLK] = &lsio_can0_hclk.common.hw, + [CLK_CAN0_CLK] = &lsio_can0_clk.common.hw, + [CLK_CAN1_HCLK] = &lsio_can1_hclk.common.hw, + [CLK_CAN1_CLK] = &lsio_can1_clk.common.hw, + [CLK_CAN0_TIMER_CLK] = &lsio_can0_timer_clk.common.hw, + [CLK_CAN1_TIMER_CLK] = &lsio_can1_timer_clk.common.hw, +}; + +static const struct atlantis_prcm_data atlantis_prcm_rcpu_data = { + .hws = atlantis_rcpu_clks, + .num = ARRAY_SIZE(atlantis_rcpu_clks), + .reset_name = "rcpu-reset" +}; + +static int atlantis_prcm_clocks_register(struct device *dev, + struct regmap *regmap, + const struct atlantis_prcm_data *data) +{ + struct clk_hw_onecell_data *clk_data; + int i, ret; + size_t num_clks = data->num; + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + for (i = 0; i < data->num; i++) { + struct clk_hw *hw = data->hws[i]; + struct atlantis_clk_common *common = + hw_to_atlantis_clk_common(hw); + common->regmap = regmap; + + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ret; + + clk_data->hws[common->clkid] = hw; + } + + clk_data->num = num_clks; + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); +} + +static int atlantis_prcm_probe(struct platform_device *pdev) +{ + const struct atlantis_prcm_data *data; + struct auxiliary_device *reset_adev; + struct regmap *regmap; + void __iomem *base; + struct device *dev = &pdev->dev; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "Failed to map registers\n"); + + regmap = devm_regmap_init_mmio(dev, base, &atlantis_prcm_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init regmap\n"); + + data = of_device_get_match_data(dev); + + ret = atlantis_prcm_clocks_register(dev, regmap, data); + if (ret) + return dev_err_probe(dev, ret, "failed to register clocks\n"); + + reset_adev = devm_auxiliary_device_create(dev, data->reset_name, NULL); + if (!reset_adev) + return dev_err_probe(dev, -ENODEV, "failed to register resets\n"); + + return 0; +} + +static const struct of_device_id atlantis_prcm_of_match[] = { + { + .compatible = "tenstorrent,atlantis-prcm-rcpu", + .data = &atlantis_prcm_rcpu_data, + }, + {} + +}; +MODULE_DEVICE_TABLE(of, atlantis_prcm_of_match); + +static struct platform_driver atlantis_prcm_driver = { + .probe = atlantis_prcm_probe, + .driver = { + .name = "atlantis-prcm", + .of_match_table = atlantis_prcm_of_match, + }, +}; +module_platform_driver(atlantis_prcm_driver); + +MODULE_DESCRIPTION("Tenstorrent Atlantis PRCM Clock Controller Driver"); +MODULE_AUTHOR("Anirudh Srinivasan "); +MODULE_LICENSE("GPL"); From 41b1a6760959017c4fa1dbc7c3cc318406ab1455 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 6 Mar 2026 20:20:41 +0800 Subject: [PATCH 08/19] clk: rockchip: rk3568: Add PCIe pipe clock gates The PCIe pipe clocks are currently left as orphan clocks and remain enabled indefinitely, which is suboptimal. Add the missing clock gates so the PCIe driver can explicitly manage them when not in use. In order not to break compatibility with old DTB, mark them as CLK_IGNORE_UNUSED. Signed-off-by: Shawn Lin Link: https://patch.msgid.link/1772799641-32164-1-git-send-email-shawn.lin@rock-chips.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3568.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 74eabf9b2ae2..d571c4b0c35f 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -827,6 +827,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = { RK3568_CLKGATE_CON(12), 3, GFLAGS), GATE(CLK_PCIE20_AUX_NDFT, "clk_pcie20_aux_ndft", "xin24m", 0, RK3568_CLKGATE_CON(12), 4, GFLAGS), + GATE(CLK_PCIE20_PIPE_DFT, "clk_pcie20_pipe_dft", "aclk_pipe", CLK_IGNORE_UNUSED, + RK3568_CLKGATE_CON(12), 5, GFLAGS), GATE(ACLK_PCIE30X1_MST, "aclk_pcie30x1_mst", "aclk_pipe", 0, RK3568_CLKGATE_CON(12), 8, GFLAGS), GATE(ACLK_PCIE30X1_SLV, "aclk_pcie30x1_slv", "aclk_pipe", 0, @@ -837,6 +839,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = { RK3568_CLKGATE_CON(12), 11, GFLAGS), GATE(CLK_PCIE30X1_AUX_NDFT, "clk_pcie30x1_aux_ndft", "xin24m", 0, RK3568_CLKGATE_CON(12), 12, GFLAGS), + GATE(CLK_PCIE30X1_PIPE_DFT, "clk_pcie30x1_pipe_dft", "aclk_pipe", CLK_IGNORE_UNUSED, + RK3568_CLKGATE_CON(12), 13, GFLAGS), GATE(ACLK_PCIE30X2_MST, "aclk_pcie30x2_mst", "aclk_pipe", 0, RK3568_CLKGATE_CON(13), 0, GFLAGS), GATE(ACLK_PCIE30X2_SLV, "aclk_pcie30x2_slv", "aclk_pipe", 0, @@ -847,6 +851,8 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = { RK3568_CLKGATE_CON(13), 3, GFLAGS), GATE(CLK_PCIE30X2_AUX_NDFT, "clk_pcie30x2_aux_ndft", "xin24m", 0, RK3568_CLKGATE_CON(13), 4, GFLAGS), + GATE(CLK_PCIE30X2_PIPE_DFT, "clk_pcie30x2_pipe_dft", "aclk_pipe", CLK_IGNORE_UNUSED, + RK3568_CLKGATE_CON(13), 5, GFLAGS), GATE(ACLK_SATA0, "aclk_sata0", "aclk_pipe", 0, RK3568_CLKGATE_CON(11), 0, GFLAGS), GATE(CLK_SATA0_PMALIVE, "clk_sata0_pmalive", "gpll_20m", 0, From fca8688a6798f6fee6b86ce0bc39d1cd0b1c8b8a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 17 Mar 2026 13:19:52 +0100 Subject: [PATCH 09/19] clk: imx: pll14xx: Use unsigned format specifier The debug outputs use %d for clock rates resulting in negative clock rate during rate calculation. Signed-off-by: Alexander Stein Reviewed-by: Peng Fan Reviewed-by: Daniel Baluta Link: https://patch.msgid.link/20260317121953.1100619-1-alexander.stein@ew.tq-group.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-pll14xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 7552aaafc339..39600ee22be3 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -151,7 +151,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat /* First try if we can get the desired rate from one of the static entries */ tt = imx_get_pll_settings(pll, rate); if (tt) { - pr_debug("%s: in=%ld, want=%ld, Using PLL setting from table\n", + pr_debug("%s: in=%lu, want=%lu, Using PLL setting from table\n", clk_hw_get_name(&pll->hw), prate, rate); t->rate = tt->rate; t->mdiv = tt->mdiv; @@ -173,7 +173,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat if (rate >= rate_min && rate <= rate_max) { kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate); - pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n", + pr_debug("%s: in=%lu, want=%lu Only adjust kdiv %ld -> %d\n", clk_hw_get_name(&pll->hw), prate, rate, FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv); fout = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); @@ -211,7 +211,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat } } found: - pr_debug("%s: in=%ld, want=%ld got=%d (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n", + pr_debug("%s: in=%lu, want=%lu got=%u (pdiv=%d sdiv=%d mdiv=%d kdiv=%d)\n", clk_hw_get_name(&pll->hw), prate, rate, t->rate, t->pdiv, t->sdiv, t->mdiv, t->kdiv); } From e2f8311a6aa5f809bb62de61888292e58087fd21 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 13 Mar 2026 08:07:31 +0100 Subject: [PATCH 10/19] clk: imx: fracn-gppll: Add 333.333333 MHz support Some parallel panels have a pixelclk of 33.30 MHz. Add support for 333.333333 MHz so a by 10 divider can be used to derive the exact pixelclk. Signed-off-by: Alexander Stein Reviewed-by: Abel Vesa Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260313070740.585043-2-alexander.stein@ew.tq-group.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-fracn-gppll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 89ed7749bf47..fe6ee77ba148 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -88,6 +88,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), + PLL_FRACN_GP(333333333U, 125, 0, 1, 1, 9), PLL_FRACN_GP(332600000U, 138, 584, 1000, 0, 10), PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12), PLL_FRACN_GP(241900000U, 201, 584, 1000, 0, 20), From a15840f7c3d7f7cac208df9c3a0dc651ebbfa80a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 13 Mar 2026 08:07:32 +0100 Subject: [PATCH 11/19] clk: imx: fracn-gppll: Add 477.4MHz support Add the 477.4MHz frequency support that can be used for display with pixelclk of 68.2 MHz. The divider of 7 is important for LVDS output on imx93. It is also usable for parallel output. Reviewed-by: Peng Fan Signed-off-by: Alexander Stein Link: https://patch.msgid.link/20260313070740.585043-3-alexander.stein@ew.tq-group.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-fracn-gppll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index fe6ee77ba148..4048c16c0578 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -85,6 +85,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8), PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), + PLL_FRACN_GP(477400000U, 119, 35, 100, 0, 6), PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), From 4b84d496c804b470124cd3a08e928df6801d8eae Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Tue, 3 Feb 2026 22:07:57 +0800 Subject: [PATCH 12/19] clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() The function pll6_bypassed() calls of_parse_phandle_with_args() but never calls of_node_put() to release the reference, causing a memory leak. Fix this by adding proper cleanup calls on all exit paths. Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") Signed-off-by: Felix Gu Reviewed-by: Frank Li Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx6q.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index f726c00aba72..5549ef6c3117 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -238,8 +238,11 @@ static bool pll6_bypassed(struct device_node *node) return false; if (clkspec.np == node && - clkspec.args[0] == IMX6QDL_PLL6_BYPASS) + clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { + of_node_put(clkspec.np); break; + } + of_node_put(clkspec.np); } /* PLL6 bypass is not part of the assigned clock list */ @@ -249,6 +252,9 @@ static bool pll6_bypassed(struct device_node *node) ret = of_parse_phandle_with_args(node, "assigned-clock-parents", "#clock-cells", index, &clkspec); + if (!ret) + of_node_put(clkspec.np); + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) return true; From 9faf207208951460f3f7eefbc112246c8d28ff1b Mon Sep 17 00:00:00 2001 From: Felix Gu Date: Tue, 3 Feb 2026 22:07:58 +0800 Subject: [PATCH 13/19] clk: imx: imx6q: Fix device node reference leak in of_assigned_ldb_sels() The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() but never calls of_node_put() to release the reference, causing a memory leak. Fix this by adding proper cleanup calls on all exit paths. Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") Signed-off-by: Felix Gu Reviewed-by: Frank Li Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx6q.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 5549ef6c3117..35e6b59c01db 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, } if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { pr_err("ccm: parent clock %d not in ccm\n", index); + of_node_put(clkspec.np); return; } parent = clkspec.args[0]; + of_node_put(clkspec.np); rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells", index, &clkspec); @@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, return; if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { pr_err("ccm: child clock %d not in ccm\n", index); + of_node_put(clkspec.np); return; } child = clkspec.args[0]; + of_node_put(clkspec.np); if (child != IMX6QDL_CLK_LDB_DI0_SEL && child != IMX6QDL_CLK_LDB_DI1_SEL) From f2c2fc93b4a3efdfcf3805ab74741826d343ff2c Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Thu, 12 Feb 2026 16:57:50 +0800 Subject: [PATCH 14/19] clk: imx: imx8-acm: fix flags for acm clocks Currently, the flags for the ACM clocks are set to 0. This configuration causes the fsl-sai audio driver to fail when attempting to set the sysclk, returning an EINVAL error. The following error messages highlight the issue: fsl-sai 59090000.sai: ASoC: error at snd_soc_dai_set_sysclk on 59090000.sai: -22 imx-hdmi sound-hdmi: failed to set cpu sysclk: -22 By setting the flag CLK_SET_RATE_NO_REPARENT, we signal that the ACM driver does not support reparenting and instead relies on the clock tree as defined in the device tree. This change resolves the issue with the fsl-sai audio driver. CC: stable@vger.kernel.org Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Signed-off-by: Stefan Eichenberger Signed-off-by: Shengjiu Wang Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260212085750.3253187-1-shengjiu.wang@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 790f7e44b11e..07dca6f31cf8 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -371,7 +371,8 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) for (i = 0; i < priv->soc_data->num_sels; i++) { hws[sels[i].clkid] = devm_clk_hw_register_mux_parent_data_table(dev, sels[i].name, sels[i].parents, - sels[i].num_parents, 0, + sels[i].num_parents, + CLK_SET_RATE_NO_REPARENT, base + sels[i].reg, sels[i].shift, sels[i].width, 0, NULL, NULL); From f5fd9ccf2d46ee7ef5b8ba645d3173116677cf7c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 29 Jan 2026 10:54:39 +0100 Subject: [PATCH 15/19] clk: vf610: Move VF610_CLK_END define to clk-vf610 driver The VF610_CLK_END was previously defined in vf610-clock.h to indicate the number of clocks. It is solely used in the clk driver to allocate proper size of the clk table. Moreover, when new clocks (like e.g. ones for MTIP L2 switch) are defined its value also changes, so it shall be locally adjusted. Signed-off-by: Lukasz Majewski Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260129095442.1646748-2-lukma@nabladev.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-vf610.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 41eb38552a9c..fddd493caf09 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -11,6 +11,13 @@ #include "clk.h" +/* + * The VF610_CLK_END corresponds to ones defined in + * include/dt-bindings/clock/vf610-clock.h + * It shall be the value of the last defined clock +1 + */ +#define VF610_CLK_END 191 + #define CCM_CCR (ccm_base + 0x00) #define CCM_CSR (ccm_base + 0x04) #define CCM_CCSR (ccm_base + 0x08) From 2f4788cca881d965188900843905c57aadd7855c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 29 Jan 2026 10:54:40 +0100 Subject: [PATCH 16/19] dt-bindings: clock: vf610: Drop VF610_CLK_END define The VF610_CLK_END should be dropped as it is not part of the ABI. Signed-off-by: Lukasz Majewski Acked-by: Rob Herring (Arm) Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260129095442.1646748-3-lukma@nabladev.com Signed-off-by: Abel Vesa --- include/dt-bindings/clock/vf610-clock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index 373644e46747..c91fb86fa9a1 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -197,6 +197,5 @@ #define VF610_CLK_TCON1 188 #define VF610_CLK_CAAM 189 #define VF610_CLK_CRC 190 -#define VF610_CLK_END 191 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ From 77f18a1f7dde3bc04c72f8623f9f4c218924301c Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 29 Jan 2026 10:54:41 +0100 Subject: [PATCH 17/19] dt-bindings: clock: vf610: Add definitions for MTIP L2 switch This patch adds VF610_CLK_ESW and VF610_CLK_ESW_MAC_TAB{0123} macros definitions for L2 switch. Those definitions describe clocks for MoreThanIP switch IP block; the switch itself and the MAC address lookup table clocks. Signed-off-by: Lukasz Majewski Acked-by: Rob Herring (Arm) Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260129095442.1646748-4-lukma@nabladev.com Signed-off-by: Abel Vesa --- include/dt-bindings/clock/vf610-clock.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index c91fb86fa9a1..5d94bd561a2e 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -197,5 +197,10 @@ #define VF610_CLK_TCON1 188 #define VF610_CLK_CAAM 189 #define VF610_CLK_CRC 190 +#define VF610_CLK_ESW 191 +#define VF610_CLK_ESW_MAC_TAB0 192 +#define VF610_CLK_ESW_MAC_TAB1 193 +#define VF610_CLK_ESW_MAC_TAB2 194 +#define VF610_CLK_ESW_MAC_TAB3 195 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ From d5dd8c523686153e29bc3e5ae0f854e13545535d Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 29 Jan 2026 10:54:42 +0100 Subject: [PATCH 18/19] clk: vf610: Add support for the Ethernet switch clocks The vf610 device has built in the MoreThanIP L2 switch. For proper operation it is required to enable ESW and MAC table lookup clocks. The MAC table spans from 0x400E_C000 for 0x4000 and it is necessary to provide clocks for each AIPS1-"slot", which size is 0x1000 (hence four separate entries). Those can be enabled via clock gating CCM_CCGR10 register (0x4006_B068). Signed-off-by: Lukasz Majewski Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260129095442.1646748-5-lukma@nabladev.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-vf610.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index fddd493caf09..1fbd8011fde2 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -16,7 +16,7 @@ * include/dt-bindings/clock/vf610-clock.h * It shall be the value of the last defined clock +1 */ -#define VF610_CLK_END 191 +#define VF610_CLK_END 196 #define CCM_CCR (ccm_base + 0x00) #define CCM_CSR (ccm_base + 0x04) @@ -320,6 +320,11 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23); clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0)); clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1)); + clk[VF610_CLK_ESW] = imx_clk_gate2("esw", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_ESW_MAC_TAB0] = imx_clk_gate2("esw_tab0", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(12)); + clk[VF610_CLK_ESW_MAC_TAB1] = imx_clk_gate2("esw_tab1", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_ESW_MAC_TAB2] = imx_clk_gate2("esw_tab2", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(14)); + clk[VF610_CLK_ESW_MAC_TAB3] = imx_clk_gate2("esw_tab3", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(15)); clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7)); From d16f57caa78776e6e8a88b96cb2597797b376138 Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Wed, 28 Jan 2026 00:47:21 +0100 Subject: [PATCH 19/19] clk: imx8mq: Correct the CSI PHY sels According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have SYSTEM_PLL2_DIV3 available as their second source, which corresponds to sys2_pll_333m rather than sys2_pll_125m. Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") Signed-off-by: Sebastian Krzyszkowiak Reviewed-by: Peng Fan Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8mq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index f70ed231b92d..cedc8a02aa1f 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; -static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", +static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", @@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; -static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", +static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",