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@xxxxxxx> > --- > 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@xxxxxxx>"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/clk/spacemit/ccu_common.h b/drivers/clk/spacemit/ccu_common.h > ...