Re: [PATCH v4 3/4] clk: spacemit: Add clock support for Spacemit K1 SoC

Samuel Holland
2025-01-16T05:25:29Z

Hi Haylen,

On 2025-01-03 3:56 PM, Haylen Chu wrote:
> The clock tree of K1 SoC contains three main types of clock hardware
> (PLL/DDN/MIX) and is managed by several independent controllers in
> different SoC parts (APBC, APBS and etc.), thus different compatible
> strings are added to distinguish them.

I was surprised that your DT binding didn't describe any clocks produced by one
of these blocks and consumed by another one of them, so I took a look at the driver.

> Some controllers may share IO region with reset controller and other low
> speed peripherals like watchdog, so all register operations are done
> through regmap to avoid competition.
>
> Signed-off-by: Haylen Chu <heylenay@4d2.org>
> ---
> drivers/clk/Kconfig | 1 +
> drivers/clk/Makefile | 1 +
> drivers/clk/spacemit/Kconfig | 20 +
> drivers/clk/spacemit/Makefile | 5 +
> drivers/clk/spacemit/ccu-k1.c | 1747 +++++++++++++++++++++++++++++
> drivers/clk/spacemit/ccu_common.h | 51 +
> drivers/clk/spacemit/ccu_ddn.c | 140 +++
> drivers/clk/spacemit/ccu_ddn.h | 84 ++
> drivers/clk/spacemit/ccu_mix.c | 304 +++++
> drivers/clk/spacemit/ccu_mix.h | 309 +++++
> drivers/clk/spacemit/ccu_pll.c | 189 ++++
> drivers/clk/spacemit/ccu_pll.h | 80 ++
> 12 files changed, 2931 insertions(+)
> create mode 100644 drivers/clk/spacemit/Kconfig
> create mode 100644 drivers/clk/spacemit/Makefile
> create mode 100644 drivers/clk/spacemit/ccu-k1.c
> create mode 100644 drivers/clk/spacemit/ccu_common.h
> create mode 100644 drivers/clk/spacemit/ccu_ddn.c
> create mode 100644 drivers/clk/spacemit/ccu_ddn.h
> create mode 100644 drivers/clk/spacemit/ccu_mix.c
> create mode 100644 drivers/clk/spacemit/ccu_mix.h
> create mode 100644 drivers/clk/spacemit/ccu_pll.c
> create mode 100644 drivers/clk/spacemit/ccu_pll.h
>
> ...
>
> +/* APBS clocks start */
> +
> +/* Frequency of pll{1,2} should not be updated at runtime */
> +static const struct ccu_pll_rate_tbl pll1_rate_tbl[] = {
> + CCU_PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
> +};
> +
> +static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = {
> + CCU_PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
> +};
> +
> +static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = {
> + CCU_PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
> + CCU_PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab),
> + CCU_PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
> +};
> +
> +static CCU_PLL_DEFINE(pll1, "pll1", pll1_rate_tbl,
> + APB_SPARE1_REG, APB_SPARE2_REG, APB_SPARE3_REG,
> + MPMU_POSR, POSR_PLL1_LOCK, CLK_SET_RATE_GATE);
> +static CCU_PLL_DEFINE(pll2, "pll2", pll2_rate_tbl,
> + APB_SPARE7_REG, APB_SPARE8_REG, APB_SPARE9_REG,
> + MPMU_POSR, POSR_PLL2_LOCK, CLK_SET_RATE_GATE);
> +static CCU_PLL_DEFINE(pll3, "pll3", pll3_rate_tbl,
> + APB_SPARE10_REG, APB_SPARE11_REG, APB_SPARE12_REG,
> + MPMU_POSR, POSR_PLL3_LOCK, 0);
> +
> +static CCU_GATE_FACTOR_DEFINE(pll1_d2, "pll1_d2", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(1), BIT(1), 0, 2, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d3, "pll1_d3", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(2), BIT(2), 0, 3, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d4, "pll1_d4", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(3), BIT(3), 0, 4, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d5, "pll1_d5", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(4), BIT(4), 0, 5, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d6, "pll1_d6", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(5), BIT(5), 0, 6, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d7, "pll1_d7", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(6), BIT(6), 0, 7, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d8, "pll1_d8", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(7), BIT(7), 0, 8, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d11_223p4, "pll1_d11_223p4", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(15), BIT(15), 0, 11, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d13_189, "pll1_d13_189", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(16), BIT(16), 0, 13, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d23_106p8, "pll1_d23_106p8", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(20), BIT(20), 0, 23, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_d64_38p4, "pll1_d64_38p4", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(0), BIT(0), 0, 64, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_aud_245p7, "pll1_aud_245p7", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(10), BIT(10), 0, 10, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll1_aud_24p5, "pll1_aud_24p5", CCU_PARENT_HW(pll1),
> + APB_SPARE2_REG,
> + BIT(11), BIT(11), 0, 100, 1, 0);
> +
> +static CCU_GATE_FACTOR_DEFINE(pll2_d1, "pll2_d1", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(0), BIT(0), 0, 1, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d2, "pll2_d2", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(1), BIT(1), 0, 2, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d3, "pll2_d3", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(2), BIT(2), 0, 3, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d4, "pll2_d4", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(3), BIT(3), 0, 4, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d5, "pll2_d5", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(4), BIT(4), 0, 5, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d6, "pll2_d6", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(5), BIT(5), 0, 6, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d7, "pll2_d7", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(6), BIT(6), 0, 7, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll2_d8, "pll2_d8", CCU_PARENT_HW(pll2),
> + APB_SPARE8_REG,
> + BIT(7), BIT(7), 0, 8, 1, 0);
> +
> +static CCU_GATE_FACTOR_DEFINE(pll3_d1, "pll3_d1", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(0), BIT(0), 0, 1, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d2, "pll3_d2", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(1), BIT(1), 0, 2, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d3, "pll3_d3", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(2), BIT(2), 0, 3, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d4, "pll3_d4", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(3), BIT(3), 0, 4, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d5, "pll3_d5", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(4), BIT(4), 0, 5, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d6, "pll3_d6", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(5), BIT(5), 0, 6, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d7, "pll3_d7", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(6), BIT(6), 0, 7, 1, 0);
> +static CCU_GATE_FACTOR_DEFINE(pll3_d8, "pll3_d8", CCU_PARENT_HW(pll3),
> + APB_SPARE11_REG,
> + BIT(7), BIT(7), 0, 8, 1, 0);
> +
> +static CCU_FACTOR_DEFINE(pll3_20, "pll3_20", CCU_PARENT_HW(pll3_d8), 20, 1);
> +static CCU_FACTOR_DEFINE(pll3_40, "pll3_40", CCU_PARENT_HW(pll3_d8), 10, 1);
> +static CCU_FACTOR_DEFINE(pll3_80, "pll3_80", CCU_PARENT_HW(pll3_d8), 5, 1);
> +
> +/* APBS clocks end */
> +
> +/* MPMU clocks start */
> +static CCU_GATE_DEFINE(pll1_d8_307p2, "pll1_d8_307p2", CCU_PARENT_HW(pll1_d8),
> + MPMU_ACGR,
> + BIT(13), BIT(13), 0, 0);

Here you have a clk_hw from one driver instance (pll1_d8_307p2) pointing to a
clk_hw from another driver instance (pll1_d8). If the consumer instance is
probed first, pll1_d8 won't have been registered with the clock core, so you are
quite likely to dereference a null hw->core pointer.

The normal way to handle relationships between clock controller instances is by
referencing the clocks in the consumer's devicetree node, and using .fw_name in
the parent_data. Unfortunately, it seems there are quite a lot of clocks that
would need to be included in the DT binding to do that.

Regards,
Samuel

> ...
> +/* APMU clocks end */
> +
> +static struct clk_hw_onecell_data k1_ccu_apbs_clks = {
> + .hws = {
> + [CLK_PLL1] = &pll1.common.hw,
> + [CLK_PLL2] = &pll2.common.hw,
> + [CLK_PLL3] = &pll3.common.hw,
> + [CLK_PLL1_D2] = &pll1_d2.common.hw,
> + [CLK_PLL1_D3] = &pll1_d3.common.hw,
> + [CLK_PLL1_D4] = &pll1_d4.common.hw,
> + [CLK_PLL1_D5] = &pll1_d5.common.hw,
> + [CLK_PLL1_D6] = &pll1_d6.common.hw,
> + [CLK_PLL1_D7] = &pll1_d7.common.hw,
> + [CLK_PLL1_D8] = &pll1_d8.common.hw,

referring to here ^

> + [CLK_PLL1_D11] = &pll1_d11_223p4.common.hw,
> + [CLK_PLL1_D13] = &pll1_d13_189.common.hw,
> + [CLK_PLL1_D23] = &pll1_d23_106p8.common.hw,
> + [CLK_PLL1_D64] = &pll1_d64_38p4.common.hw,
> + [CLK_PLL1_D10_AUD] = &pll1_aud_245p7.common.hw,
> + [CLK_PLL1_D100_AUD] = &pll1_aud_24p5.common.hw,
> + [CLK_PLL2_D1] = &pll2_d1.common.hw,
> + [CLK_PLL2_D2] = &pll2_d2.common.hw,
> + [CLK_PLL2_D3] = &pll2_d3.common.hw,
> + [CLK_PLL2_D4] = &pll2_d4.common.hw,
> + [CLK_PLL2_D5] = &pll2_d5.common.hw,
> + [CLK_PLL2_D6] = &pll2_d6.common.hw,
> + [CLK_PLL2_D7] = &pll2_d7.common.hw,
> + [CLK_PLL2_D8] = &pll2_d8.common.hw,
> + [CLK_PLL3_D1] = &pll3_d1.common.hw,
> + [CLK_PLL3_D2] = &pll3_d2.common.hw,
> + [CLK_PLL3_D3] = &pll3_d3.common.hw,
> + [CLK_PLL3_D4] = &pll3_d4.common.hw,
> + [CLK_PLL3_D5] = &pll3_d5.common.hw,
> + [CLK_PLL3_D6] = &pll3_d6.common.hw,
> + [CLK_PLL3_D7] = &pll3_d7.common.hw,
> + [CLK_PLL3_D8] = &pll3_d8.common.hw,
> + [CLK_PLL3_80] = &pll3_80.common.hw,
> + [CLK_PLL3_40] = &pll3_40.common.hw,
> + [CLK_PLL3_20] = &pll3_20.common.hw,
> +
> + },
> + .num = CLK_APBS_NUM,
> +};
> +
> +static struct clk_hw_onecell_data k1_ccu_mpmu_clks = {
> + .hws = {
> + [CLK_PLL1_307P2] = &pll1_d8_307p2.common.hw,

from here ^

> + [CLK_PLL1_76P8] = &pll1_d32_76p8.common.hw,
> + [CLK_PLL1_61P44] = &pll1_d40_61p44.common.hw,
> + [CLK_PLL1_153P6] = &pll1_d16_153p6.common.hw,
> + [CLK_PLL1_102P4] = &pll1_d24_102p4.common.hw,
> + [CLK_PLL1_51P2] = &pll1_d48_51p2.common.hw,
> + [CLK_PLL1_51P2_AP] = &pll1_d48_51p2_ap.common.hw,
> + [CLK_PLL1_57P6] = &pll1_m3d128_57p6.common.hw,
> + [CLK_PLL1_25P6] = &pll1_d96_25p6.common.hw,
> + [CLK_PLL1_12P8] = &pll1_d192_12p8.common.hw,
> + [CLK_PLL1_12P8_WDT] = &pll1_d192_12p8_wdt.common.hw,
> + [CLK_PLL1_6P4] = &pll1_d384_6p4.common.hw,
> + [CLK_PLL1_3P2] = &pll1_d768_3p2.common.hw,
> + [CLK_PLL1_1P6] = &pll1_d1536_1p6.common.hw,
> + [CLK_PLL1_0P8] = &pll1_d3072_0p8.common.hw,
> + [CLK_PLL1_351] = &pll1_d7_351p08.common.hw,
> + [CLK_PLL1_409P6] = &pll1_d6_409p6.common.hw,
> + [CLK_PLL1_204P8] = &pll1_d12_204p8.common.hw,
> + [CLK_PLL1_491] = &pll1_d5_491p52.common.hw,
> + [CLK_PLL1_245P76] = &pll1_d10_245p76.common.hw,
> + [CLK_PLL1_614] = &pll1_d4_614p4.common.hw,
> + [CLK_PLL1_47P26] = &pll1_d52_47p26.common.hw,
> + [CLK_PLL1_31P5] = &pll1_d78_31p5.common.hw,
> + [CLK_PLL1_819] = &pll1_d3_819p2.common.hw,
> + [CLK_PLL1_1228] = &pll1_d2_1228p8.common.hw,
> + [CLK_SLOW_UART] = &slow_uart.common.hw,
> + [CLK_SLOW_UART1] = &slow_uart1_14p74.common.hw,
> + [CLK_SLOW_UART2] = &slow_uart2_48.common.hw,
> + [CLK_WDT] = &wdt_clk.common.hw,
> + [CLK_RIPC] = &ripc_clk.common.hw,
> + [CLK_I2S_SYSCLK] = &i2s_sysclk.common.hw,
> + [CLK_I2S_BCLK] = &i2s_bclk.common.hw,
> + [CLK_APB] = &apb_clk.common.hw,
> + [CLK_WDT_BUS] = &wdt_bus_clk.common.hw,
> + },
> + .num = CLK_MPMU_NUM,
> +};
> +
> +static struct clk_hw_onecell_data k1_ccu_apbc_clks = {
> + .hws = {
> + [CLK_UART0] = &uart0_clk.common.hw,
> + [CLK_UART2] = &uart2_clk.common.hw,
> + [CLK_UART3] = &uart3_clk.common.hw,
> + [CLK_UART4] = &uart4_clk.common.hw,
> + [CLK_UART5] = &uart5_clk.common.hw,
> + [CLK_UART6] = &uart6_clk.common.hw,
> + [CLK_UART7] = &uart7_clk.common.hw,
> + [CLK_UART8] = &uart8_clk.common.hw,
> + [CLK_UART9] = &uart9_clk.common.hw,
> + [CLK_GPIO] = &gpio_clk.common.hw,
> + [CLK_PWM0] = &pwm0_clk.common.hw,
> + [CLK_PWM1] = &pwm1_clk.common.hw,
> + [CLK_PWM2] = &pwm2_clk.common.hw,
> + [CLK_PWM3] = &pwm3_clk.common.hw,
> + [CLK_PWM4] = &pwm4_clk.common.hw,
> + [CLK_PWM5] = &pwm5_clk.common.hw,
> + [CLK_PWM6] = &pwm6_clk.common.hw,
> + [CLK_PWM7] = &pwm7_clk.common.hw,
> + [CLK_PWM8] = &pwm8_clk.common.hw,
> + [CLK_PWM9] = &pwm9_clk.common.hw,
> + [CLK_PWM10] = &pwm10_clk.common.hw,
> + [CLK_PWM11] = &pwm11_clk.common.hw,
> + [CLK_PWM12] = &pwm12_clk.common.hw,
> + [CLK_PWM13] = &pwm13_clk.common.hw,
> + [CLK_PWM14] = &pwm14_clk.common.hw,
> + [CLK_PWM15] = &pwm15_clk.common.hw,
> + [CLK_PWM16] = &pwm16_clk.common.hw,
> + [CLK_PWM17] = &pwm17_clk.common.hw,
> + [CLK_PWM18] = &pwm18_clk.common.hw,
> + [CLK_PWM19] = &pwm19_clk.common.hw,
> + [CLK_SSP3] = &ssp3_clk.common.hw,
> + [CLK_RTC] = &rtc_clk.common.hw,
> + [CLK_TWSI0] = &twsi0_clk.common.hw,
> + [CLK_TWSI1] = &twsi1_clk.common.hw,
> + [CLK_TWSI2] = &twsi2_clk.common.hw,
> + [CLK_TWSI4] = &twsi4_clk.common.hw,
> + [CLK_TWSI5] = &twsi5_clk.common.hw,
> + [CLK_TWSI6] = &twsi6_clk.common.hw,
> + [CLK_TWSI7] = &twsi7_clk.common.hw,
> + [CLK_TWSI8] = &twsi8_clk.common.hw,
> + [CLK_TIMERS1] = &timers1_clk.common.hw,
> + [CLK_TIMERS2] = &timers2_clk.common.hw,
> + [CLK_AIB] = &aib_clk.common.hw,
> + [CLK_ONEWIRE] = &onewire_clk.common.hw,
> + [CLK_SSPA0] = &sspa0_clk.common.hw,
> + [CLK_SSPA1] = &sspa1_clk.common.hw,
> + [CLK_DRO] = &dro_clk.common.hw,
> + [CLK_IR] = &ir_clk.common.hw,
> + [CLK_TSEN] = &tsen_clk.common.hw,
> + [CLK_IPC_AP2AUD] = &ipc_ap2aud_clk.common.hw,
> + [CLK_CAN0] = &can0_clk.common.hw,
> + [CLK_CAN0_BUS] = &can0_bus_clk.common.hw,
> + [CLK_UART0_BUS] = &uart0_bus_clk.common.hw,
> + [CLK_UART2_BUS] = &uart2_bus_clk.common.hw,
> + [CLK_UART3_BUS] = &uart3_bus_clk.common.hw,
> + [CLK_UART4_BUS] = &uart4_bus_clk.common.hw,
> + [CLK_UART5_BUS] = &uart5_bus_clk.common.hw,
> + [CLK_UART6_BUS] = &uart6_bus_clk.common.hw,
> + [CLK_UART7_BUS] = &uart7_bus_clk.common.hw,
> + [CLK_UART8_BUS] = &uart8_bus_clk.common.hw,
> + [CLK_UART9_BUS] = &uart9_bus_clk.common.hw,
> + [CLK_GPIO_BUS] = &gpio_bus_clk.common.hw,
> + [CLK_PWM0_BUS] = &pwm0_bus_clk.common.hw,
> + [CLK_PWM1_BUS] = &pwm1_bus_clk.common.hw,
> + [CLK_PWM2_BUS] = &pwm2_bus_clk.common.hw,
> + [CLK_PWM3_BUS] = &pwm3_bus_clk.common.hw,
> + [CLK_PWM4_BUS] = &pwm4_bus_clk.common.hw,
> + [CLK_PWM5_BUS] = &pwm5_bus_clk.common.hw,
> + [CLK_PWM6_BUS] = &pwm6_bus_clk.common.hw,
> + [CLK_PWM7_BUS] = &pwm7_bus_clk.common.hw,
> + [CLK_PWM8_BUS] = &pwm8_bus_clk.common.hw,
> + [CLK_PWM9_BUS] = &pwm9_bus_clk.common.hw,
> + [CLK_PWM10_BUS] = &pwm10_bus_clk.common.hw,
> + [CLK_PWM11_BUS] = &pwm11_bus_clk.common.hw,
> + [CLK_PWM12_BUS] = &pwm12_bus_clk.common.hw,
> + [CLK_PWM13_BUS] = &pwm13_bus_clk.common.hw,
> + [CLK_PWM14_BUS] = &pwm14_bus_clk.common.hw,
> + [CLK_PWM15_BUS] = &pwm15_bus_clk.common.hw,
> + [CLK_PWM16_BUS] = &pwm16_bus_clk.common.hw,
> + [CLK_PWM17_BUS] = &pwm17_bus_clk.common.hw,
> + [CLK_PWM18_BUS] = &pwm18_bus_clk.common.hw,
> + [CLK_PWM19_BUS] = &pwm19_bus_clk.common.hw,
> + [CLK_SSP3_BUS] = &ssp3_bus_clk.common.hw,
> + [CLK_RTC_BUS] = &rtc_bus_clk.common.hw,
> + [CLK_TWSI0_BUS] = &twsi0_bus_clk.common.hw,
> + [CLK_TWSI1_BUS] = &twsi1_bus_clk.common.hw,
> + [CLK_TWSI2_BUS] = &twsi2_bus_clk.common.hw,
> + [CLK_TWSI4_BUS] = &twsi4_bus_clk.common.hw,
> + [CLK_TWSI5_BUS] = &twsi5_bus_clk.common.hw,
> + [CLK_TWSI6_BUS] = &twsi6_bus_clk.common.hw,
> + [CLK_TWSI7_BUS] = &twsi7_bus_clk.common.hw,
> + [CLK_TWSI8_BUS] = &twsi8_bus_clk.common.hw,
> + [CLK_TIMERS1_BUS] = &timers1_bus_clk.common.hw,
> + [CLK_TIMERS2_BUS] = &timers2_bus_clk.common.hw,
> + [CLK_AIB_BUS] = &aib_bus_clk.common.hw,
> + [CLK_ONEWIRE_BUS] = &onewire_bus_clk.common.hw,
> + [CLK_SSPA0_BUS] = &sspa0_bus_clk.common.hw,
> + [CLK_SSPA1_BUS] = &sspa1_bus_clk.common.hw,
> + [CLK_TSEN_BUS] = &tsen_bus_clk.common.hw,
> + [CLK_IPC_AP2AUD_BUS] = &ipc_ap2aud_bus_clk.common.hw,
> + },
> + .num = CLK_APBC_NUM,
> +};
> +
> +static struct clk_hw_onecell_data k1_ccu_apmu_clks = {
> + .hws = {
> + [CLK_CCI550] = &cci550_clk.common.hw,
> + [CLK_CPU_C0_HI] = &cpu_c0_hi_clk.common.hw,
> + [CLK_CPU_C0_CORE] = &cpu_c0_core_clk.common.hw,
> + [CLK_CPU_C0_ACE] = &cpu_c0_ace_clk.common.hw,
> + [CLK_CPU_C0_TCM] = &cpu_c0_tcm_clk.common.hw,
> + [CLK_CPU_C1_HI] = &cpu_c1_hi_clk.common.hw,
> + [CLK_CPU_C1_CORE] = &cpu_c1_core_clk.common.hw,
> + [CLK_CPU_C1_ACE] = &cpu_c1_ace_clk.common.hw,
> + [CLK_CCIC_4X] = &ccic_4x_clk.common.hw,
> + [CLK_CCIC1PHY] = &ccic1phy_clk.common.hw,
> + [CLK_SDH_AXI] = &sdh_axi_aclk.common.hw,
> + [CLK_SDH0] = &sdh0_clk.common.hw,
> + [CLK_SDH1] = &sdh1_clk.common.hw,
> + [CLK_SDH2] = &sdh2_clk.common.hw,
> + [CLK_USB_P1] = &usb_p1_aclk.common.hw,
> + [CLK_USB_AXI] = &usb_axi_clk.common.hw,
> + [CLK_USB30] = &usb30_clk.common.hw,
> + [CLK_QSPI] = &qspi_clk.common.hw,
> + [CLK_QSPI_BUS] = &qspi_bus_clk.common.hw,
> + [CLK_DMA] = &dma_clk.common.hw,
> + [CLK_AES] = &aes_clk.common.hw,
> + [CLK_VPU] = &vpu_clk.common.hw,
> + [CLK_GPU] = &gpu_clk.common.hw,
> + [CLK_EMMC] = &emmc_clk.common.hw,
> + [CLK_EMMC_X] = &emmc_x_clk.common.hw,
> + [CLK_AUDIO] = &audio_clk.common.hw,
> + [CLK_HDMI] = &hdmi_mclk.common.hw,
> + [CLK_PMUA_ACLK] = &pmua_aclk.common.hw,
> + [CLK_PCIE0] = &pcie0_clk.common.hw,
> + [CLK_PCIE1] = &pcie1_clk.common.hw,
> + [CLK_PCIE2] = &pcie2_clk.common.hw,
> + [CLK_EMAC0_BUS] = &emac0_bus_clk.common.hw,
> + [CLK_EMAC0_PTP] = &emac0_ptp_clk.common.hw,
> + [CLK_EMAC1_BUS] = &emac1_bus_clk.common.hw,
> + [CLK_EMAC1_PTP] = &emac1_ptp_clk.common.hw,
> + [CLK_JPG] = &jpg_clk.common.hw,
> + [CLK_CCIC2PHY] = &ccic2phy_clk.common.hw,
> + [CLK_CCIC3PHY] = &ccic3phy_clk.common.hw,
> + [CLK_CSI] = &csi_clk.common.hw,
> + [CLK_CAMM0] = &camm0_clk.common.hw,
> + [CLK_CAMM1] = &camm1_clk.common.hw,
> + [CLK_CAMM2] = &camm2_clk.common.hw,
> + [CLK_ISP_CPP] = &isp_cpp_clk.common.hw,
> + [CLK_ISP_BUS] = &isp_bus_clk.common.hw,
> + [CLK_ISP] = &isp_clk.common.hw,
> + [CLK_DPU_MCLK] = &dpu_mclk.common.hw,
> + [CLK_DPU_ESC] = &dpu_esc_clk.common.hw,
> + [CLK_DPU_BIT] = &dpu_bit_clk.common.hw,
> + [CLK_DPU_PXCLK] = &dpu_pxclk.common.hw,
> + [CLK_DPU_HCLK] = &dpu_hclk.common.hw,
> + [CLK_DPU_SPI] = &dpu_spi_clk.common.hw,
> + [CLK_DPU_SPI_HBUS] = &dpu_spi_hbus_clk.common.hw,
> + [CLK_DPU_SPIBUS] = &dpu_spi_bus_clk.common.hw,
> + [CLK_DPU_SPI_ACLK] = &dpu_spi_aclk.common.hw,
> + [CLK_V2D] = &v2d_clk.common.hw,
> + [CLK_EMMC_BUS] = &emmc_bus_clk.common.hw,
> + },
> + .num = CLK_APMU_NUM
> +};
> +
> +struct spacemit_ccu_data {
> + struct clk_hw_onecell_data *hw_clks;
> + bool need_pll_lock;
> +};
> +
> +struct spacemit_ccu_priv {
> + const struct spacemit_ccu_data *data;
> + struct regmap *base;
> + struct regmap *lock_base;
> +};
> +
> +static int spacemit_ccu_register(struct device *dev,
> + struct spacemit_ccu_priv *priv)
> +{
> + const struct spacemit_ccu_data *data = priv->data;
> + int i, ret;
> +
> + for (i = 0; i < data->hw_clks->num; i++) {
> + struct clk_hw *hw = data->hw_clks->hws[i];
> + struct ccu_common *common;
> + const char *name;
> +
> + if (!hw)
> + continue;
> +
> + common = hw_to_ccu_common(hw);
> + name = hw->init->name;
> +
> + common->base = priv->base;
> + common->lock_base = priv->lock_base;
> +
> + ret = devm_clk_hw_register(dev, hw);
> + if (ret) {
> + dev_err(dev, "Cannot register clock %d - %s\n",
> + i, name);
> + return ret;
> + }
> + }
> +
> + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> + data->hw_clks);
> +}
> +
> +static int k1_ccu_probe(struct platform_device *pdev)
> +{
> + const struct spacemit_ccu_data *data;
> + struct regmap *base_map, *lock_map = NULL;
> + struct device *dev = &pdev->dev;
> + struct spacemit_ccu_priv *priv;
> + struct device_node *parent;
> + int ret;
> +
> + data = of_device_get_match_data(dev);
> + if (WARN_ON(!data))
> + return -EINVAL;
> +
> + parent = of_get_parent(dev->of_node);
> + base_map = syscon_node_to_regmap(parent);
> + of_node_put(parent);
> +
> + if (IS_ERR(base_map))
> + return dev_err_probe(dev, PTR_ERR(base_map),
> + "failed to get regmap\n");
> +
> + if (data->need_pll_lock) {
> + lock_map = syscon_regmap_lookup_by_phandle(dev->of_node,
> + "spacemit,mpmu");
> + if (IS_ERR(lock_map))
> + return dev_err_probe(dev, PTR_ERR(lock_map),
> + "failed to get lock regmap\n");
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->data = data;
> + priv->base = base_map;
> + priv->lock_base = lock_map;
> +
> + ret = spacemit_ccu_register(dev, priv);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to register clocks\n");
> +
> + return 0;
> +}
> +
> +static const struct spacemit_ccu_data k1_ccu_apbs_data = {
> + .need_pll_lock = true,
> + .hw_clks = &k1_ccu_apbs_clks,
> +};
> +
> +static const struct spacemit_ccu_data k1_ccu_mpmu_data = {
> + .need_pll_lock = false,
> + .hw_clks = &k1_ccu_mpmu_clks,
> +};
> +
> +static const struct spacemit_ccu_data k1_ccu_apbc_data = {
> + .need_pll_lock = false,
> + .hw_clks = &k1_ccu_apbc_clks,
> +};
> +
> +static const struct spacemit_ccu_data k1_ccu_apmu_data = {
> + .need_pll_lock = false,
> + .hw_clks = &k1_ccu_apmu_clks,
> +};
> +
> +static const struct of_device_id of_k1_ccu_match[] = {
> + {
> + .compatible = "spacemit,k1-ccu-apbs",
> + .data = &k1_ccu_apbs_data,
> + },
> + {
> + .compatible = "spacemit,k1-ccu-mpmu",
> + .data = &k1_ccu_mpmu_data,
> + },
> + {
> + .compatible = "spacemit,k1-ccu-apbc",
> + .data = &k1_ccu_apbc_data,
> + },
> + {
> + .compatible = "spacemit,k1-ccu-apmu",
> + .data = &k1_ccu_apmu_data,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, of_k1_ccu_match);
> +
> +static struct platform_driver k1_ccu_driver = {
> + .driver = {
> + .name = "spacemit,k1-ccu",
> + .of_match_table = of_k1_ccu_match,
> + },
> + .probe = k1_ccu_probe,
> +};
> +module_platform_driver(k1_ccu_driver);
> +
> +MODULE_DESCRIPTION("Spacemit K1 CCU driver");
> +MODULE_AUTHOR("Haylen Chu <heylenay@4d2.org>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/clk/spacemit/ccu_common.h b/drivers/clk/spacemit/ccu_common.h
> ...