[PATCH v2 04/10] clk: sunxi-ng: add CCU drivers for V853

András Szemző szemzo.andras at gmail.com
Thu Feb 20 01:28:43 PST 2025


Hi,

Thanks for your review!

> On 19 Feb 2025, at 21:21, Jernej Škrabec <jernej.skrabec at gmail.com> wrote:
> 
> Dne sreda, 5. februar 2025 ob 13:52:19 Srednjeevropski standardni čas je Andras Szemzo napisal(a):
>> V853 has similar gates/resets like existing Allwinner SOCs. Add support for it's CCU and PRCM CCU.
>> 
>> Signed-off-by: Andras Szemzo <szemzo.andras at gmail.com>
>> ---
>> drivers/clk/sunxi-ng/Kconfig            |   10 +
>> drivers/clk/sunxi-ng/Makefile           |    4 +
>> drivers/clk/sunxi-ng/ccu-sun8i-v853-r.c |  120 +++
>> drivers/clk/sunxi-ng/ccu-sun8i-v853-r.h |   14 +
>> drivers/clk/sunxi-ng/ccu-sun8i-v853.c   | 1145 +++++++++++++++++++++++
>> drivers/clk/sunxi-ng/ccu-sun8i-v853.h   |   14 +
>> 6 files changed, 1307 insertions(+)
>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-v853-r.c
>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-v853-r.h
>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-v853.c
>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-v853.h
>> 
>> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
>> index b547198a2c65..e257373177e0 100644
>> --- a/drivers/clk/sunxi-ng/Kconfig
>> +++ b/drivers/clk/sunxi-ng/Kconfig
>> @@ -12,6 +12,16 @@ config SUNIV_F1C100S_CCU
>> default y
>> depends on MACH_SUNIV || COMPILE_TEST
>> 
>> +config SUN8I_V853_CCU
>> + tristate "Support for the Allwinner V853/V851s/V851SE CCU"
>> + default MACH_SUN8I
>> + depends on MACH_SUN8I || COMPILE_TEST
>> +
>> +config SUN8I_V853_R_CCU
>> + tristate "Support for the Allwinner V853/V851s/V851SE PRCM CCU"
>> + default MACH_SUN8I
>> + depends on MACH_SUN8I || COMPILE_TEST
> 
> Generally, this are two patches, one for each driver.
> 
>> +
>> config SUN20I_D1_CCU
>> tristate "Support for the Allwinner D1/R528/T113 CCU"
>> default y
>> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
>> index 6b3ae2b620db..b87928462e15 100644
>> --- a/drivers/clk/sunxi-ng/Makefile
>> +++ b/drivers/clk/sunxi-ng/Makefile
>> @@ -25,6 +25,8 @@ sunxi-ccu-y += ccu_mp.o
>> 
>> # SoC support
>> obj-$(CONFIG_SUNIV_F1C100S_CCU) += suniv-f1c100s-ccu.o
>> +obj-$(CONFIG_SUN8I_V853_CCU) += sun8i-v853-ccu.o
>> +obj-$(CONFIG_SUN8I_V853_R_CCU) += sun8i-v853-r-ccu.o
> 
> Put it to other sun8i drivers.
> 
>> obj-$(CONFIG_SUN20I_D1_CCU) += sun20i-d1-ccu.o
>> obj-$(CONFIG_SUN20I_D1_R_CCU) += sun20i-d1-r-ccu.o
>> obj-$(CONFIG_SUN50I_A64_CCU) += sun50i-a64-ccu.o
>> @@ -50,6 +52,8 @@ obj-$(CONFIG_SUN9I_A80_CCU) += sun9i-a80-de-ccu.o
>> obj-$(CONFIG_SUN9I_A80_CCU) += sun9i-a80-usb-ccu.o
>> 
>> suniv-f1c100s-ccu-y += ccu-suniv-f1c100s.o
>> +sun8i-v853-ccu-y += ccu-sun8i-v853.o
>> +sun8i-v853-r-ccu-y += ccu-sun8i-v853-r.o
> 
> Ditto.
> 

ok

>> sun20i-d1-ccu-y += ccu-sun20i-d1.o
>> sun20i-d1-r-ccu-y += ccu-sun20i-d1-r.o
>> sun50i-a64-ccu-y += ccu-sun50i-a64.o
>> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.c
>> new file mode 100644
>> index 000000000000..bd60e00cda7f
>> --- /dev/null
>> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.c
>> @@ -0,0 +1,120 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2025 Andras Szemzo <szemzo.andras at gmail.com>
>> + *
>> + * Based on ccu-sun20i-d1-r.c by Samuel Holland.
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "ccu_common.h"
>> +#include "ccu_reset.h"
>> +
>> +#include "ccu_gate.h"
>> +#include "ccu_mp.h"
>> +
>> +#include "ccu-sun8i-v853-r.h"
>> +
>> +static const struct clk_parent_data r_ahb_apb0_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .fw_name = "losc" },
>> + { .fw_name = "iosc" },
>> + { .fw_name = "pll-periph" },
>> + { .fw_name = "pll-audio" }
>> +};
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX(r_ahb_clk, "r-ahb",
>> +  r_ahb_apb0_parents, 0x000,
>> +  0, 5, /* M */
>> +  8, 2, /* P */
>> +  24, 3, /* mux */
>> +  0);
>> +static const struct clk_hw *r_ahb_hw = &r_ahb_clk.common.hw;
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX(r_apb0_clk, "r-apb0",
>> +  r_ahb_apb0_parents, 0x00c,
>> +  0, 5, /* M */
>> +  8, 2, /* P */
>> +  24, 3, /* mux */
>> +  0);
>> +static const struct clk_hw *r_apb0_hw = &r_apb0_clk.common.hw;
> 
> Where can I look for above clocks? There are not described in BSP driver.
> 

As the original BSP’s PRCM driver has an unacceptable licence, I had to rewrite this driver.  This IP block
isn’t documented in the V853 manual, so as Andre suggested, I used the A523 manual, and the D1/T113
PRCM driver. Than I peek/poke the registers to check if it’s valid or not. 

awboot> read32 0x701000c
0x0701000c: 0x0f00031f
awboot> read32 0x7010000
0x07010000: 0x00000000
awboot> write32 0x7010000 0xffffffff
awboot> read32 0x7010000
0x07010000: 0x0700031f

They are there, I’m not sure about it’s usage.


>> +
>> +static SUNXI_CCU_GATE_HWS(bus_r_twd_clk, "bus-r-twd", &r_apb0_hw, 
>> +  0x12c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_r_ppu_clk, "bus-r-ppu", &r_apb0_hw,
>> +  0x1ac, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_r_rtc_clk, "bus-r-rtc", &r_ahb_hw,
>> +  0x20c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_r_cpucfg_clk, "bus-r-cpucfg", &r_apb0_hw,
>> +  0x22c, BIT(0), 0);
>> +
>> +static struct ccu_common *sun8i_v853_r_ccu_clks[] = {
>> + &r_ahb_clk.common,
>> + &r_apb0_clk.common,
>> + &bus_r_twd_clk.common,
>> + &bus_r_ppu_clk.common,
>> + &bus_r_rtc_clk.common,
>> + &bus_r_cpucfg_clk.common,
>> +};
>> +
>> +static struct clk_hw_onecell_data sun8i_v853_r_hw_clks = {
>> + .num = CLK_NUMBER,
>> + .hws = {
>> + [CLK_R_AHB] = &r_ahb_clk.common.hw,
>> + [CLK_R_APB0] = &r_apb0_clk.common.hw,
>> + [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw,
>> + [CLK_BUS_R_PPU] = &bus_r_ppu_clk.common.hw,
>> + [CLK_BUS_R_RTC] = &bus_r_rtc_clk.common.hw,
>> + [CLK_BUS_R_CPUCFG] = &bus_r_cpucfg_clk.common.hw,
>> + },
>> +};
>> +
>> +static const struct ccu_reset_map sun8i_v853_r_ccu_resets[] = {
>> + [RST_BUS_R_TWD] = { 0x12c, BIT(16) },
> 
> Where did you get that? BSP driver that I checked doesn't mentions it.
> 

yes, just double checked and this bit is not valid, sorry, I’ll remove it.

>> + [RST_BUS_R_PPU] = { 0x1ac, BIT(16) },
>> + [RST_BUS_R_RTC] = { 0x20c, BIT(16) },
>> + [RST_BUS_R_CPUCFG] = { 0x22c, BIT(16) },
>> +};
>> +
>> +static const struct sunxi_ccu_desc sun8i_v853_r_ccu_desc = {
>> + .ccu_clks = sun8i_v853_r_ccu_clks,
>> + .num_ccu_clks = ARRAY_SIZE(sun8i_v853_r_ccu_clks),
>> +
>> + .hw_clks = &sun8i_v853_r_hw_clks,
>> +
>> + .resets = sun8i_v853_r_ccu_resets,
>> + .num_resets = ARRAY_SIZE(sun8i_v853_r_ccu_resets),
>> +};
>> +
>> +static int sun8i_v853_r_ccu_probe(struct platform_device *pdev)
>> +{
>> + void __iomem *reg;
>> +
>> + reg = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(reg))
>> + return PTR_ERR(reg);
>> +
>> + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_v853_r_ccu_desc);
>> +}
>> +
>> +static const struct of_device_id sun8i_v853_r_ccu_ids[] = {
>> + { .compatible = "allwinner,sun8i-v853-r-ccu" },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_v853_r_ccu_ids);
>> +
>> +static struct platform_driver sun8i_v853_r_ccu_driver = {
>> + .probe = sun8i_v853_r_ccu_probe,
>> + .driver = {
>> + .name = "sun8i-v853-r-ccu",
>> + .suppress_bind_attrs = true,
>> + .of_match_table = sun8i_v853_r_ccu_ids,
>> + },
>> +};
>> +module_platform_driver(sun8i_v853_r_ccu_driver);
>> +
>> +MODULE_IMPORT_NS("SUNXI_CCU");
>> +MODULE_DESCRIPTION("Support for the Allwinner V853 PRCM CCU");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.h b/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.h
>> new file mode 100644
>> index 000000000000..2c6cc7b6f251
>> --- /dev/null
>> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v853-r.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2025 Andras Szemzo <szemzo.andras at gmail.com>
>> + */
>> +
>> +#ifndef _CCU_SUN8I_V853_R_H
>> +#define _CCU_SUN8I_V853_R_H
>> +
>> +#include <dt-bindings/clock/allwinner,sun8i-v853-r-ccu.h>
>> +#include <dt-bindings/reset/allwinner,sun8i-v853-r-ccu.h>
>> +
>> +#define CLK_NUMBER (CLK_BUS_R_CPUCFG + 1)
>> +
>> +#endif
>> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v853.c b/drivers/clk/sunxi-ng/ccu-sun8i-v853.c
>> new file mode 100644
>> index 000000000000..4b32f3a913cf
>> --- /dev/null
>> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v853.c
>> @@ -0,0 +1,1145 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2025 Andras Szemzo <szemzo.andras at gmail.com>
>> + *
>> + * Based on ccu-sun20i-d1.c by Samuel Holland.
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "../clk.h"
>> +
>> +#include "ccu_common.h"
>> +#include "ccu_reset.h"
>> +
>> +#include "ccu_div.h"
>> +#include "ccu_gate.h"
>> +#include "ccu_mp.h"
>> +#include "ccu_mult.h"
>> +#include "ccu_nk.h"
>> +#include "ccu_nkm.h"
>> +#include "ccu_nkmp.h"
>> +#include "ccu_nm.h"
>> +
>> +#include "ccu-sun8i-v853.h"
>> +
>> +static const struct clk_parent_data osc24M[] = {
>> + { .fw_name = "hosc" }
>> +};
>> +
>> +/*
>> + * For the CPU PLL, the output divider is described as "only for testing"
>> + * in the user manual. So it's not modelled and forced to 0.
>> + */
>> +#define SUN8I_V853_PLL_CPU_REG 0x000
>> +
>> +static struct ccu_mult pll_cpu_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .common = {
>> + .reg = 0x000,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu", osc24M,
>> +   &ccu_mult_ops,
>> +   CLK_SET_RATE_GATE),
>> + },
>> +};
>> +
>> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>> +#define SUN8I_V853_PLL_DDR_REG 0x010
>> +static struct ccu_nkmp pll_ddr_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
>> + .common = {
>> + .reg = 0x010,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-ddr", osc24M,
>> +   &ccu_nkmp_ops,
>> +   CLK_SET_RATE_GATE),
>> + },
>> +};
>> +
>> +#define SUN8I_V853_PLL_PERIPH_REG 0x020
>> +static struct ccu_nm pll_periph_4x_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
>> + .common = {
>> + .reg = 0x020,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-periph-4x", osc24M,
>> +   &ccu_nm_ops,
>> +   CLK_SET_RATE_GATE),
>> + },
>> +};
>> +
>> +static const struct clk_hw *pll_periph_4x_hws[] = {
>> + &pll_periph_4x_clk.common.hw
>> +};
>> +
>> +static SUNXI_CCU_M_HWS(pll_periph_2x_clk, "pll-periph-2x", pll_periph_4x_hws,
>> +       0x020, 16, 3, 0);
>> +
>> +static SUNXI_CCU_M_HWS(pll_periph_800M_clk, "pll-periph-800M", pll_periph_4x_hws,
>> +       0x020, 20, 3, 0);
>> +
>> +static SUNXI_CCU_M_HWS(pll_periph_480M_clk, "pll-periph-480M", pll_periph_4x_hws,
>> +       0x020, 2, 3, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_600M_clk, "pll-periph-600M",
>> +   &pll_periph_2x_clk.common.hw, 2, 1, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_400M_clk, "pll-periph-400M",
>> +   &pll_periph_2x_clk.common.hw, 3, 1, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_300M_clk, "pll-periph-300M",
>> +   &pll_periph_600M_clk.hw, 2, 1, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_200M_clk, "pll-periph-200M",
>> +   &pll_periph_400M_clk.hw, 2, 1, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_160M_clk, "pll-periph-160M",
>> +   &pll_periph_480M_clk.common.hw, 3, 1, 0);
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_periph_150M_clk, "pll-periph-150M",
>> +   &pll_periph_300M_clk.hw, 2, 1, 0);
>> +
>> +/*
>> + * For Video PLLs, the output divider is described as "only for testing"
>> + * in the user manual.
>> + */
>> +#define SUN8I_V853_PLL_VIDEO_REG 0x040
>> +static struct ccu_nkmp pll_video_4x_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .p = _SUNXI_CCU_DIV(1, 1), /* input divider */
>> + .common = {
>> + .reg = 0x040,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-video-4x", osc24M,
>> +   &ccu_nkmp_ops,
>> +   CLK_SET_RATE_GATE),
>> + },
>> +};
>> +
>> +static const struct clk_hw *pll_video_4x_hws[] = {
>> + &pll_video_4x_clk.common.hw
>> +};
>> +static CLK_FIXED_FACTOR_HWS(pll_video_2x_clk, "pll-video-2x",
>> +    pll_video_4x_hws, 2, 1, CLK_SET_RATE_PARENT);
>> +static CLK_FIXED_FACTOR_HWS(pll_video_1x_clk, "pll-video-1x",
>> +    pll_video_4x_hws, 4, 1, CLK_SET_RATE_PARENT);
>> +
>> +
>> +/*
>> + * For CSI PLLs, the output divider is described as "only for testing"
>> + * in the user manual.
>> + */
>> +#define SUN8I_V853_PLL_CSI_REG 0x048
>> +static struct ccu_nkmp pll_csi_4x_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .p = _SUNXI_CCU_DIV(1, 1), /* input divider */
>> + .common = {
>> + .reg = 0x048,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-csi-4x", osc24M,
>> +   &ccu_nkmp_ops,
>> +   CLK_SET_RATE_GATE),
>> + },
>> +};
>> +
>> +static CLK_FIXED_FACTOR_HW(pll_csi_clk, "pll-csi",
>> +   &pll_csi_4x_clk.common.hw, 4, 1, CLK_SET_RATE_PARENT);
>> +
>> +
>> +#define SUN8I_V853_PLL_AUDIO_REG 0x078
>> +static struct ccu_sdm_setting pll_audio_div5_sdm_table[] = {
>> + { .rate = 196608000, .pattern = 0xc001eb85, .m = 5, .n = 40 }, /* 24.576 */
>> + { .rate = 67737600, .pattern = 0xc001288d, .m = 8, .n = 22 }, /* 22.5792 */
>> +};
>> +
>> +static struct ccu_nm pll_audio_div5_clk = {
>> + .enable = BIT(27),
>> + .lock           = BIT(28),
>> + .n              = _SUNXI_CCU_MULT(8, 8),
>> + .m              = _SUNXI_CCU_DIV(20, 3),
>> + .sdm            = _SUNXI_CCU_SDM(pll_audio_div5_sdm_table,
>> +    BIT(24), 0x0178, BIT(31)),
>> + .common         = {
>> + .reg            = 0x0078,
>> + .features       = CCU_FEATURE_SIGMA_DELTA_MOD,
>> + .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-audio-div5", osc24M,
>> +   &ccu_nm_ops,
>> +   CLK_SET_RATE_UNGATE),
>> + },
>> +};
>> +
>> +static const struct clk_hw *pll_audio_div5_hws[] = {
>> + &pll_audio_div5_clk.common.hw
>> +};
>> +
>> +static SUNXI_CCU_M_HWS(pll_audio_1x_clk, "pll-audio-1x", pll_audio_div5_hws,
>> +       0xe00, 0, 5, CLK_SET_RATE_PARENT);
>> +
>> +/* pll-audio-div2 and pll-audio-4x not used, because pll-audio-1x can cover 
>> + * 22.5792M and 24.576M 
>> + */
>> +static SUNXI_CCU_M(pll_audio_div2_clk, "pll-audio-div2", "pll-audio",
>> +   0x078, 16, 3, 0);
>> +static SUNXI_CCU_M(pll_audio_4x_clk, "pll-audio-4x", "pll-audio-div2",
>> +   0xe00, 5, 5, 0);
>> +
>> +/*
>> + * For the NPU PLL, the output divider is described as "only for testing"
>> + * in the user manual.
>> + */
>> +#define SUN8I_V853_PLL_NPU_REG 0x080
>> +static struct ccu_nkmp pll_npu_4x_clk = {
>> + .enable = BIT(27),
>> + .lock = BIT(28),
>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 11),
>> + .p = _SUNXI_CCU_DIV(1, 1), /* input divider */
>> + .common = {
>> + .reg = 0x080,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-npu-4x", osc24M,
>> +   &ccu_nkmp_ops,
>> +   CLK_SET_RATE_UNGATE),
>> + },
>> +};
>> +
>> +/*
>> + * The CPU gate is not modelled - it is in a separate register (0x504)
>> + * and has a special key field. The clock must not be gated anyway by
>> + * the kernel.
>> + */
>> +static const struct clk_parent_data cpu_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .fw_name = "losc" },
>> + { .fw_name = "iosc" },
>> + { .hw = &pll_cpu_clk.common.hw },
>> + { .hw = &pll_periph_600M_clk.hw },
>> + { .hw = &pll_periph_800M_clk.common.hw },
>> +};
>> +
>> +/*
>> + * There is a P factor (PLL_OUT_EXT_DIVP[17:16]) in this register, but it is not modeled.
>> + * The manual states that it should be used only, when the output clock is less than 288 MHz.
>> + */
>> +static SUNXI_CCU_MUX_DATA(cpu_clk, "cpu", cpu_parents,
>> +  0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
>> +
>> +static const struct clk_hw *cpu_hws[] = { &cpu_clk.common.hw };
>> +
>> +static SUNXI_CCU_M_HWS(cpu_axi_clk, "cpu-axi", cpu_hws,
>> +       0x500, 0, 2, 0);
>> +static SUNXI_CCU_M_HWS(cpu_apb_clk, "cpu-apb", cpu_hws,
>> +       0x500, 8, 2, 0);
>> +
>> +static const struct clk_parent_data ahb_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .fw_name = "losc" },
>> + { .fw_name = "iosc" },
>> + { .hw = &pll_periph_600M_clk.hw },
>> +};
>> +static SUNXI_CCU_MP_DATA_WITH_MUX(ahb_clk, "ahb", ahb_parents, 0x510,
>> +  0, 5, /* M */
>> +  8, 2, /* P */
>> +  24, 2, /* mux */
>> +  0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX(apb0_clk, "apb0", ahb_parents, 0x520,
>> +  0, 5, /* M */
>> +  8, 2, /* P */
>> +  24, 2, /* mux */
>> +  0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX(apb1_clk, "apb1", ahb_parents, 0x524,
>> +  0, 5, /* M */
>> +  8, 2, /* P */
>> +  24, 2, /* mux */
>> +  0);
>> +
>> +static const struct clk_hw *ahb_hws[] = { &ahb_clk.common.hw };
>> +static const struct clk_hw *apb0_hws[] = { &apb0_clk.common.hw };
>> +static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw };
>> +
>> +
>> +static const struct clk_hw *de_g2d_parents[] = {
>> + &pll_periph_300M_clk.hw,
>> + &pll_video_1x_clk.hw,
>> +};
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(de_clk, "de", de_g2d_parents, 0x600,
>> +    0, 5, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_de_clk, "bus-de", ahb_hws,
>> +  0x60c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", de_g2d_parents, 0x630,
>> +    0, 5, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_g2d_clk, "bus-g2d", ahb_hws,
>> +  0x63c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_parent_data ce_parents[] = {
>> + { .fw_name = "hosc" },
> 
> Where this come from? V853 manual v1.1 doesn't have it.

There is a sun8iw21 ccu driver [1], where hosc is the first parent:

[1]:
https://github.com/YuzukiHD/TinyVision/blob/main/kernel/bsp/drivers/clk/sunxi-ng/ccu-sun8iw21.c#L262

I don’t know if the manual or if this driver is the correct.

> 
>> + { .hw = &pll_periph_400M_clk.hw, },
>> + { .hw = &pll_periph_300M_clk.hw, }
>> +};
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680,
>> +      0, 4, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      CLK_SET_RATE_PARENT);
> 
> Set rate parent flag doesn't make sense on constant parents.

yes

> 
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_ce_clk, "bus-ce", ahb_hws,
>> +  0x68c, BIT(0) | BIT(1), 0);
>> +
>> +static const struct clk_hw *ve_parents[] = {
>> + &pll_periph_300M_clk.hw,
>> + &pll_periph_400M_clk.hw,
>> + &pll_periph_480M_clk.common.hw,
>> + &pll_npu_4x_clk.common.hw,
>> + &pll_video_4x_clk.common.hw,
>> + &pll_csi_4x_clk.common.hw,
>> +};
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690,
>> +    0, 5, /* M */
>> +    24, 3, /* mux */
>> +    BIT(31), /* gate */
>> +    0);
> 
> CLK_SET_RATE_PARENT flag? Cedrus driver set working clock at the beginning.
> 

ok

>> +
>> +static SUNXI_CCU_GATE_HWS(bus_ve_clk, "bus-ve", ahb_hws,
>> +  0x69c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_hw *npu_parents[] = {
>> + &pll_periph_480M_clk.common.hw,
>> + &pll_periph_600M_clk.hw,
>> + &pll_periph_800M_clk.common.hw,
>> + &pll_npu_4x_clk.common.hw,
>> +};
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(npu_clk, "npu", npu_parents, 0x6e0,
>> +    0, 5, /* M */
>> +    24, 3, /* mux */
>> +    BIT(31), /* gate */
>> +    0);
> 
> I think CLK_SET_RATE_PARENT would also be beneficial here.

I tried to mimic how the BSP setup the NPU clocks (as I think, not sure), in the dts I setup it like:

                npu: npu at 3050000 {
                        compatible = "vivante,gc";
                        reg = <0x03050000 0x1000>;
                        interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "npu";
                        clocks = <&ccu CLK_BUS_NPU>, <&ccu CLK_NPU>;
                        clock-names = "bus", "core";
                        assigned-clocks = <&ccu CLK_PLL_NPU_4X>, <&ccu CLK_NPU>;
                        assigned-clock-parents = <&dcxo>, <&ccu CLK_PLL_NPU_4X>;
                        assigned-clock-rates =  <1392000000>, <348000000>;
                        resets = <&ccu RST_BUS_NPU>;
                        iommus = <&iommu 6>;
                        power-domains = <&ppu PD_NPU>;
                };

With these settings (after adding a reset support to the etnaviv driver) at least I'm able to dump some registers via debugfs.
Do you think I should add the CLK_SET_RATE_PARENT flag?

> 
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_npu_clk, "bus-npu", ahb_hws,
>> +  0x6ec, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", ahb_hws,
>> +  0x70c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_msgbox0_clk, "bus-msgbox0", ahb_hws,
>> +  0x71c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_msgbox1_clk, "bus-msgbox1", ahb_hws,
>> +  0x71c, BIT(1), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_spinlock_clk, "bus-spinlock", ahb_hws,
>> +  0x72c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_hstimer_clk, "bus-hstimer", ahb_hws,
>> +  0x73c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_DATA(avs_clk, "avs", osc24M,
>> +   0x740, BIT(31), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_dbg_clk, "bus-dbg", ahb_hws,
>> +  0x78c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_pwm_clk, "bus-pwm", apb0_hws,
>> +  0x7ac, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", ahb_hws,
>> +  0x7bc, BIT(0), 0);
>> +
>> +static const struct clk_hw *dram_parents[] = {
>> + &pll_ddr_clk.common.hw,
>> + &pll_periph_2x_clk.common.hw,
>> + &pll_periph_800M_clk.common.hw,
>> +};
>> +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dram_clk, "dram", dram_parents, 0x800,
>> +     0, 5, /* M */
>> +     8, 2, /* P */
>> +     24, 3, /* mux */
>> +     BIT(31), CLK_IS_CRITICAL);
> 
> This clock needs update field to be set to actually apply configuration. So
> same comment as on A523 clock version, this needs new flag to be introduced
> for such case.
> 

ok

>> +
>> +static CLK_FIXED_FACTOR_HW(mbus_clk, "mbus",
>> +   &dram_clk.common.hw, 4, 1, 0);
>> +
>> +static const struct clk_hw *mbus_hws[] = { &mbus_clk.hw };
>> +
>> +static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws,
>> +  0x804, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(mbus_ve_clk, "mbus-ve", mbus_hws,
>> +  0x804, BIT(1), 0);
>> +static SUNXI_CCU_GATE_HWS(mbus_ce_clk, "mbus-ce", mbus_hws,
>> +  0x804, BIT(2), 0);
>> +static SUNXI_CCU_GATE_HWS(mbus_csi_clk, "mbus-csi", mbus_hws,
>> +  0x804, BIT(8), 0);
>> +static SUNXI_CCU_GATE_HWS(mbus_isp_clk, "mbus-isp", mbus_hws,
>> +  0x804, BIT(9), 0);
>> +static SUNXI_CCU_GATE_HWS(mbus_g2d_clk, "mbus-g2d", mbus_hws,
>> +  0x804, BIT(10), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_dram_clk, "bus-dram", ahb_hws,
>> +  0x80c, BIT(0), CLK_IS_CRITICAL);
>> +
>> +
>> +static const struct clk_parent_data mmc0_mmc1_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_periph_400M_clk.hw, },
>> + { .hw = &pll_periph_300M_clk.hw, },
>> +};
> 
> Just mmc_parents.

ok

> 
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static const struct clk_parent_data mmc2_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_periph_600M_clk.hw, },
>> + { .hw = &pll_periph_400M_clk.hw, },
>> +};
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", ahb_hws,
>> +  0x84c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_mmc1_clk, "bus-mmc1", ahb_hws,
>> +  0x84c, BIT(1), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_mmc2_clk, "bus-mmc2", ahb_hws,
>> +  0x84c, BIT(2), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb1_hws,
>> +  0x90c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb1_hws,
>> +  0x90c, BIT(1), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb1_hws,
>> +  0x90c, BIT(2), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb1_hws,
>> +  0x90c, BIT(3), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_i2c0_clk, "bus-i2c0", apb1_hws,
>> +  0x91c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_i2c1_clk, "bus-i2c1", apb1_hws,
>> +  0x91c, BIT(1), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws,
>> +  0x91c, BIT(2), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws,
>> +  0x91c, BIT(3), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_i2c4_clk, "bus-i2c4", apb1_hws,
>> +  0x91c, BIT(4), 0);
>> +
>> +static const struct clk_parent_data spi_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_periph_300M_clk.hw, },
>> + { .hw = &pll_periph_200M_clk.hw, },
>> +};
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi0_clk, "spi0", spi_parents, 0x940,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi1_clk, "spi1", spi_parents, 0x944,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi2_clk, "spi2", spi_parents, 0x948,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi3_clk, "spi3", spi_parents, 0x94c,
>> +       0, 4, /* M */
>> +       8, 2, /* P */
>> +       24, 3, /* mux */
>> +       BIT(31), /* gate */
>> +       0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", ahb_hws,
>> +  0x96c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", ahb_hws,
>> +  0x96c, BIT(1), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_spi2_clk, "bus-spi2", ahb_hws,
>> +  0x96c, BIT(2), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_spi3_clk, "bus-spi3", ahb_hws,
>> +  0x96c, BIT(3), 0);
>> +
>> +
>> +static const struct clk_parent_data spif_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_periph_400M_clk.hw, },
>> + { .hw = &pll_periph_300M_clk.hw, },
>> +};
>> +
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(spif_clk, "spif", spif_parents, 0x0950,
>> +      0, 4, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      CLK_SET_RATE_PARENT);
> 
> This is MP clock, P being at 9:8.

yes, the BSP driver [1] model it with only M, I’ll update it to MP.

> 
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_spif_clk, "bus-spif", ahb_hws,
>> +  0x096c, BIT(4), 0);
>> +
>> +
>> +static const struct clk_hw *pll_periph_150M_hws[] = { &pll_periph_150M_clk.hw };
>> +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(emac_25M_clk, "emac-25M", pll_periph_150M_hws,
>> +      0x970, BIT(31) | BIT(30), 6, 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_emac_clk, "bus-emac", ahb_hws,
>> +  0x97c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_gpadc_clk, "bus-gpadc", apb0_hws,
>> +  0x9ec, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_ths_clk, "bus-ths", ahb_hws,
>> +  0x9fc, BIT(0), 0);
>> +
>> +
>> +static const struct clk_hw *audio_parents[] = {
>> + &pll_audio_1x_clk.common.hw,
>> + &pll_audio_4x_clk.common.hw,
>> +};
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2s0_clk, "i2s0", audio_parents, 0xa10,
>> +    0, 4, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(i2s1_clk, "i2s1", audio_parents, 0xa14,
>> +    0, 4, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_i2s0_clk, "bus-i2s0", ahb_hws,
>> +  0xa20, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_i2s1_clk, "bus-i2s1", ahb_hws,
>> +  0xa20, BIT(1), 0);
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(dmic_clk, "dmic", audio_parents, 0xa40,
>> +    0, 4, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", ahb_hws,
>> +  0xa4c, BIT(0), 0);
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(audio_codec_dac_clk, "audio-codec-dac", 
>> +    audio_parents, 0xa50,
>> +    0, 4, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(audio_codec_adc_clk, "audio-codec-adc", 
>> +    audio_parents, 0xa54,
>> +    0, 4, /* M */
>> +    24, 1, /* mux */
>> +    BIT(31), /* gate */
>> +    CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_audio_codec_clk, "bus-audio-codec", apb0_hws,
>> +  0xa5c, BIT(0), 0);
>> +
>> +/*
>> + * There are OHCI 12M clock source selection bits for the USB 2.0 port.
>> + * We will force them to 0 (12M divided from 48M).
>> + */
>> +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
>> +
>> +#define SUN8I_V853_USB_CLK_REG 0xa70
>> +
>> +static SUNXI_CCU_GATE(usb_ohci_clk, "usb", "osc12M", 0x0a70, BIT(31), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_ohci_clk, "bus-ohci", ahb_hws, 0xa8c, BIT(0), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_ehci_clk, "bus-ehci", ahb_hws, 0xa8c, BIT(4), 0);
>> +static SUNXI_CCU_GATE_HWS(bus_otg_clk, "bus-otg", ahb_hws, 0xa8c, BIT(8), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_dpss_top_clk, "bus-dpss-top", ahb_hws,
>> +  0xabc, BIT(0), 0);
>> +
>> +
>> +static const struct clk_parent_data mipi_dsi_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_periph_200M_clk.hw },
>> + { .hw = &pll_periph_150M_clk.hw },
>> +};
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", mipi_dsi_parents, 
>> +      0xb24,
>> +      0, 4, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      CLK_SET_RATE_PARENT);
> 
> CLK_SET_RATE_PARENT doesn't do anything for constant clocks.
> 

ok

> Best regards,
> Jernej
> 
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_mipi_dsi_clk, "bus-mipi-dsi", ahb_hws,
>> +  0xb4c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_hw *tcon_lcd_parents[] = {
>> + &pll_video_4x_clk.common.hw,
>> + &pll_periph_2x_clk.common.hw,
>> + &pll_csi_4x_clk.common.hw,
>> +};
>> +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_lcd_clk, "tcon-lcd", tcon_lcd_parents, 
>> +     0xb60,
>> +     0, 4, /* M */
>> +     8, 2, /* P */
>> +     24, 3, /* mux */
>> +     BIT(31), /* gate */
>> +     CLK_SET_RATE_PARENT);
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_tcon_lcd_clk, "bus-tcon-lcd", ahb_hws,
>> +  0xb7c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_hw *csi_top_parents[] = {
>> + &pll_periph_300M_clk.hw,
>> + &pll_periph_400M_clk.hw,
>> + &pll_video_4x_clk.common.hw,
>> + &pll_csi_4x_clk.common.hw,
>> +};
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_top_clk, "csi-top", csi_top_parents, 0xc04,
>> +    0, 5, /* M */
>> +    24, 3, /* mux */
>> +    BIT(31), /* gate */
>> +    0);
>> +
>> +
>> +static const struct clk_parent_data csi_mclk_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .hw = &pll_csi_4x_clk.common.hw },
>> + { .hw = &pll_video_4x_clk.common.hw },
>> + { .hw = &pll_periph_2x_clk.common.hw },
>> +};
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk0_clk, "csi-mclk0", csi_mclk_parents, 
>> +      0xc08,
>> +      0, 5, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      0);
>> +
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk1_clk, "csi-mclk1", csi_mclk_parents, 
>> +      0xc0c,
>> +      0, 5, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      0);
>> +
>> +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk2_clk, "csi-mclk2", csi_mclk_parents, 
>> +      0xc10,
>> +      0, 5, /* M */
>> +      24, 3, /* mux */
>> +      BIT(31), /* gate */
>> +      0);
> 
> All CSI mclks should be MP type.
> 

Again, these are from the BSP, I’ll update them.

>> +
>> +static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", ahb_hws,
>> +  0xc2c, BIT(0), 0);
>> +
>> +
>> +static SUNXI_CCU_GATE_HWS(bus_wiegand_clk, "bus-wiegand", ahb_hws,
>> +  0xc7c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_parent_data riscv_parents[] = {
>> + { .fw_name = "hosc" },
>> + { .fw_name = "losc" },
>> + { .fw_name = "iosc" },
>> + { .hw = &pll_periph_600M_clk.hw },
>> + { .hw = &pll_periph_480M_clk.common.hw },
>> + { .hw = &pll_cpu_clk.common.hw },
>> +};
>> +static SUNXI_CCU_M_DATA_WITH_MUX(riscv_clk, "riscv-cpu", riscv_parents, 0xd00,
>> + 0, 5, /* M */
>> + 24, 3, /* mux */
>> + CLK_SET_RATE_PARENT);
>> +
>> +/* The riscv-axi clk must be divided by at least 2. */
>> +static struct clk_div_table riscv_axi_table[] = {
>> + { .val = 1, .div = 2 },
>> + { .val = 2, .div = 3 },
>> + { .val = 3, .div = 4 },
>> + { /* Sentinel */ }
>> +};
>> +static SUNXI_CCU_DIV_TABLE_HW(riscv_axi_clk, "riscv-axi", &riscv_clk.common.hw,
>> +      0xd00, 8, 2, riscv_axi_table, 0);
>> +
>> +static SUNXI_CCU_GATE_HWS_WITH_KEY(riscv_core_gate, "riscv-core-gate", ahb_hws,
>> +   0xd04, BIT(0), 0);
>> +
>> +static SUNXI_CCU_GATE_HWS(riscv_cfg_gate, "riscv-cfg-gate", ahb_hws,
>> +  0xd0c, BIT(0), 0);
>> +
>> +
>> +static const struct clk_hw *pll_periph_160M_hws[] = {
>> + &pll_periph_160M_clk.hw,
>> +};
>> +
>> +static SUNXI_CCU_GATE_DATA(fanout_24M_clk, "fanout-24M", osc24M,
>> +   0xf30, BIT(0), 0);
>> +static SUNXI_CCU_GATE_DATA_WITH_PREDIV(fanout_12M_clk, "fanout-12M", osc24M,
>> +       0xf30, BIT(1), 2, 0);
>> +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph_160M_hws,
>> +      0xf30, BIT(2), 10, 0);
>> +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph_150M_hws,
>> +      0xf30, BIT(3), 6, 0);
>> +
>> +
>> +/* This clock has a second divider that is not modelled and forced to 0. */
>> +#define SUN8I_V853_FANOUT_27M_REG 0xf34
>> +static const struct clk_hw *fanout_27M_parents[] = {
>> + &pll_video_1x_clk.hw,
>> + &pll_csi_clk.hw,
>> + &pll_periph_300M_clk.hw,
>> +};
>> +static SUNXI_CCU_M_HW_WITH_MUX_GATE(fanout_27M_clk, "fanout-27M", 
>> +    fanout_27M_parents, 0xf34,
>> +    0, 5, /* M */
>> +    24, 2, /* mux */
>> +    BIT(31), /* gate */
>> +    0);
>> +static SUNXI_CCU_M_HWS_WITH_GATE(fanout_pclk_clk, "fanout-pclk", apb0_hws, 0xf38,
>> + 0, 5, /* M */
>> + BIT(31), /* gate */
>> + 0);
>> +
>> +static const struct clk_parent_data fanout_parents[] = {
>> + { .fw_name = "losc" },
>> + { .hw = &fanout_12M_clk.common.hw },
>> + { .hw = &fanout_16M_clk.common.hw },
>> + { .hw = &fanout_24M_clk.common.hw },
>> + { .hw = &fanout_25M_clk.common.hw },
>> + { .hw = &fanout_27M_clk.common.hw },
>> + { .hw = &fanout_pclk_clk.common.hw },
>> +};
>> +
>> +static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0xf3c,
>> +    0, 3, /* mux */
>> +    BIT(21), /* gate */
>> +    0);
>> +static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0xf3c,
>> +    3, 3, /* mux */
>> +    BIT(22), /* gate */
>> +    0);
>> +static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0xf3c,
>> +    6, 3, /* mux */
>> +    BIT(23), /* gate */
>> +    0);
>> +
>> +
>> +static struct ccu_common *sun8i_v853_ccu_clks[] = {
>> + &pll_cpu_clk.common,
>> + &pll_ddr_clk.common,
>> + &pll_periph_4x_clk.common,
>> + &pll_periph_2x_clk.common,
>> + &pll_periph_800M_clk.common,
>> + &pll_periph_480M_clk.common,
>> + &pll_video_4x_clk.common,
>> + &pll_csi_4x_clk.common,
>> + &pll_audio_div2_clk.common,
>> + &pll_audio_div5_clk.common,
>> + &pll_audio_4x_clk.common,
>> + &pll_audio_1x_clk.common,
>> + &pll_npu_4x_clk.common,
>> + &cpu_clk.common,
>> + &cpu_axi_clk.common,
>> + &cpu_apb_clk.common,
>> + &ahb_clk.common,
>> + &apb0_clk.common,
>> + &apb1_clk.common,
>> + &de_clk.common,
>> + &bus_de_clk.common,
>> + &g2d_clk.common,
>> + &bus_g2d_clk.common,
>> + &ce_clk.common,
>> + &bus_ce_clk.common,
>> + &ve_clk.common,
>> + &bus_ve_clk.common,
>> + &npu_clk.common,
>> + &bus_npu_clk.common,
>> + &bus_dma_clk.common,
>> + &bus_msgbox0_clk.common,
>> + &bus_msgbox1_clk.common,
>> + &bus_spinlock_clk.common,
>> + &bus_hstimer_clk.common,
>> + &avs_clk.common,
>> + &bus_dbg_clk.common,
>> + &bus_pwm_clk.common,
>> + &bus_iommu_clk.common,
>> + &dram_clk.common,
>> + &mbus_dma_clk.common,
>> + &mbus_ve_clk.common,
>> + &mbus_ce_clk.common,
>> + &mbus_csi_clk.common,
>> + &mbus_isp_clk.common,
>> + &mbus_g2d_clk.common,
>> + &bus_dram_clk.common,
>> + &mmc0_clk.common,
>> + &mmc1_clk.common,
>> + &mmc2_clk.common,
>> + &bus_mmc0_clk.common,
>> + &bus_mmc1_clk.common,
>> + &bus_mmc2_clk.common,
>> + &bus_uart0_clk.common,
>> + &bus_uart1_clk.common,
>> + &bus_uart2_clk.common,
>> + &bus_uart3_clk.common,
>> + &bus_i2c0_clk.common,
>> + &bus_i2c1_clk.common,
>> + &bus_i2c2_clk.common,
>> + &bus_i2c3_clk.common,
>> + &bus_i2c4_clk.common,
>> + &spi0_clk.common,
>> + &spi1_clk.common,
>> + &spi2_clk.common,
>> + &spi3_clk.common,
>> + &bus_spi0_clk.common,
>> + &bus_spi1_clk.common,
>> + &bus_spi2_clk.common,
>> + &bus_spi3_clk.common,
>> + &spif_clk.common,
>> + &bus_spif_clk.common,
>> + &emac_25M_clk.common,
>> + &bus_emac_clk.common,
>> + &bus_gpadc_clk.common,
>> + &bus_ths_clk.common,
>> + &usb_ohci_clk.common,
>> + &bus_ohci_clk.common,
>> + &bus_ehci_clk.common,
>> + &bus_otg_clk.common,
>> + &i2s0_clk.common,
>> + &i2s1_clk.common,
>> + &bus_i2s0_clk.common,
>> + &bus_i2s1_clk.common,
>> + &dmic_clk.common,
>> + &bus_dmic_clk.common,
>> + &audio_codec_dac_clk.common,
>> + &audio_codec_adc_clk.common,
>> + &bus_audio_codec_clk.common,
>> + &bus_dpss_top_clk.common,
>> + &mipi_dsi_clk.common,
>> + &bus_mipi_dsi_clk.common,
>> + &tcon_lcd_clk.common,
>> + &bus_tcon_lcd_clk.common,
>> + &csi_top_clk.common,
>> + &csi_mclk0_clk.common,
>> + &csi_mclk1_clk.common,
>> + &csi_mclk2_clk.common,
>> + &bus_csi_clk.common,
>> + &bus_wiegand_clk.common,
>> + &riscv_clk.common,
>> + &riscv_axi_clk.common,
>> + &riscv_core_gate.common,
>> + &riscv_cfg_gate.common,
>> + &fanout_24M_clk.common,
>> + &fanout_12M_clk.common,
>> + &fanout_16M_clk.common,
>> + &fanout_25M_clk.common,
>> + &fanout_27M_clk.common,
>> + &fanout_pclk_clk.common,
>> + &fanout0_clk.common,
>> + &fanout1_clk.common,
>> + &fanout2_clk.common,
>> +};
>> +
>> +static struct clk_hw_onecell_data sun8i_v853_hw_clks = {
>> + .num = CLK_NUMBER,
>> + .hws = {
>> + [CLK_OSC12M]            = &osc12M_clk.hw,
>> + [CLK_PLL_CPU] = &pll_cpu_clk.common.hw,
>> + [CLK_PLL_DDR] = &pll_ddr_clk.common.hw,
>> + [CLK_PLL_PERIPH_4X] = &pll_periph_4x_clk.common.hw,
>> + [CLK_PLL_PERIPH_2X] = &pll_periph_2x_clk.common.hw,
>> + [CLK_PLL_PERIPH_800M] = &pll_periph_800M_clk.common.hw,
>> + [CLK_PLL_PERIPH_480M] = &pll_periph_480M_clk.common.hw,
>> + [CLK_PLL_PERIPH_600M] = &pll_periph_600M_clk.hw,
>> + [CLK_PLL_PERIPH_400M] = &pll_periph_400M_clk.hw,
>> + [CLK_PLL_PERIPH_300M] = &pll_periph_300M_clk.hw,
>> + [CLK_PLL_PERIPH_200M] = &pll_periph_200M_clk.hw,
>> + [CLK_PLL_PERIPH_160M] = &pll_periph_160M_clk.hw,
>> + [CLK_PLL_PERIPH_150M] = &pll_periph_150M_clk.hw,
>> + [CLK_PLL_VIDEO_4X] = &pll_video_4x_clk.common.hw,
>> + [CLK_PLL_VIDEO_2X] = &pll_video_2x_clk.hw,
>> + [CLK_PLL_VIDEO_1X] = &pll_video_1x_clk.hw,
>> + [CLK_PLL_CSI_4X] = &pll_csi_4x_clk.common.hw,
>> + [CLK_PLL_AUDIO_DIV2] = &pll_audio_div2_clk.common.hw,
>> + [CLK_PLL_AUDIO_DIV5] = &pll_audio_div5_clk.common.hw,
>> + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.common.hw,
>> + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.common.hw,
>> + [CLK_PLL_NPU_4X] = &pll_npu_4x_clk.common.hw,
>> + [CLK_CPU] = &cpu_clk.common.hw,
>> + [CLK_CPU_AXI] = &cpu_axi_clk.common.hw,
>> + [CLK_CPU_APB] = &cpu_apb_clk.common.hw,
>> + [CLK_AHB] = &ahb_clk.common.hw,
>> + [CLK_APB0] = &apb0_clk.common.hw,
>> + [CLK_APB1] = &apb1_clk.common.hw,
>> + [CLK_MBUS] = &mbus_clk.hw,
>> + [CLK_DE] = &de_clk.common.hw,
>> + [CLK_BUS_DE] = &bus_de_clk.common.hw,
>> + [CLK_G2D] = &g2d_clk.common.hw,
>> + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw,
>> + [CLK_CE] = &ce_clk.common.hw,
>> + [CLK_BUS_CE] = &bus_ce_clk.common.hw,
>> + [CLK_VE] = &ve_clk.common.hw,
>> + [CLK_BUS_VE] = &bus_ve_clk.common.hw,
>> + [CLK_NPU] = &npu_clk.common.hw,
>> + [CLK_BUS_NPU] = &bus_npu_clk.common.hw,
>> + [CLK_BUS_DMA] = &bus_dma_clk.common.hw,
>> + [CLK_BUS_MSGBOX0] = &bus_msgbox0_clk.common.hw,
>> + [CLK_BUS_MSGBOX1] = &bus_msgbox1_clk.common.hw,
>> + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw,
>> + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw,
>> + [CLK_AVS] = &avs_clk.common.hw,
>> + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw,
>> + [CLK_BUS_PWM] = &bus_pwm_clk.common.hw,
>> + [CLK_BUS_IOMMU] = &bus_iommu_clk.common.hw,
>> + [CLK_DRAM] = &dram_clk.common.hw,
>> + [CLK_MBUS_DMA] = &mbus_dma_clk.common.hw,
>> + [CLK_MBUS_VE] = &mbus_ve_clk.common.hw,
>> + [CLK_MBUS_CE] = &mbus_ce_clk.common.hw,
>> + [CLK_MBUS_CSI] = &mbus_csi_clk.common.hw,
>> + [CLK_MBUS_ISP] = &mbus_isp_clk.common.hw,
>> + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw,
>> + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw,
>> + [CLK_MMC0] = &mmc0_clk.common.hw,
>> + [CLK_MMC1] = &mmc1_clk.common.hw,
>> + [CLK_MMC2] = &mmc2_clk.common.hw,
>> + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw,
>> + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw,
>> + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw,
>> + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw,
>> + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw,
>> + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw,
>> + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw,
>> + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw,
>> + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
>> + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
>> + [CLK_BUS_I2C3] = &bus_i2c3_clk.common.hw,
>> + [CLK_BUS_I2C4] = &bus_i2c4_clk.common.hw,
>> + [CLK_SPI0] = &spi0_clk.common.hw,
>> + [CLK_SPI1] = &spi1_clk.common.hw,
>> + [CLK_SPI2] = &spi2_clk.common.hw,
>> + [CLK_SPI3] = &spi3_clk.common.hw,
>> + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
>> + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw,
>> + [CLK_BUS_SPI2] = &bus_spi2_clk.common.hw,
>> + [CLK_BUS_SPI3] = &bus_spi3_clk.common.hw,
>> + [CLK_SPIF] = &spif_clk.common.hw,
>> + [CLK_BUS_SPIF] = &bus_spif_clk.common.hw,
>> + [CLK_EMAC_25M] = &emac_25M_clk.common.hw,
>> + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw,
>> + [CLK_BUS_GPADC] = &bus_gpadc_clk.common.hw,
>> + [CLK_BUS_THS] = &bus_ths_clk.common.hw,
>> + [CLK_I2S0] = &i2s0_clk.common.hw,
>> + [CLK_I2S1] = &i2s1_clk.common.hw,
>> + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw,
>> + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw,
>> + [CLK_DMIC] = &dmic_clk.common.hw,
>> + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw,
>> + [CLK_AUDIO_CODEC_DAC] = &audio_codec_dac_clk.common.hw,
>> + [CLK_AUDIO_CODEC_ADC] = &audio_codec_adc_clk.common.hw,
>> + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw,
>> + [CLK_USB_OHCI] = &usb_ohci_clk.common.hw,
>> + [CLK_BUS_OHCI] = &bus_ohci_clk.common.hw,
>> + [CLK_BUS_EHCI] = &bus_ehci_clk.common.hw,
>> + [CLK_BUS_OTG] = &bus_otg_clk.common.hw,
>> + [CLK_BUS_DPSS_TOP] = &bus_dpss_top_clk.common.hw,
>> + [CLK_MIPI_DSI] = &mipi_dsi_clk.common.hw,
>> + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw,
>> + [CLK_TCON_LCD] = &tcon_lcd_clk.common.hw,
>> + [CLK_BUS_TCON_LCD] = &bus_tcon_lcd_clk.common.hw,
>> + [CLK_CSI_TOP] = &csi_top_clk.common.hw,
>> + [CLK_CSI_MCLK0] = &csi_mclk0_clk.common.hw,
>> + [CLK_CSI_MCLK1] = &csi_mclk1_clk.common.hw,
>> + [CLK_CSI_MCLK2] = &csi_mclk2_clk.common.hw,
>> + [CLK_BUS_CSI] = &bus_csi_clk.common.hw,
>> + [CLK_BUS_WIEGAND] = &bus_wiegand_clk.common.hw,
>> + [CLK_RISCV] = &riscv_clk.common.hw,
>> + [CLK_RISCV_AXI] = &riscv_axi_clk.common.hw,
>> + [CLK_RISCV_CORE_GATE]   = &riscv_core_gate.common.hw,
>> + [CLK_RISCV_CFG_GATE]    = &riscv_cfg_gate.common.hw,
>> + [CLK_FANOUT_24M] = &fanout_24M_clk.common.hw,
>> + [CLK_FANOUT_16M] = &fanout_16M_clk.common.hw,
>> + [CLK_FANOUT_12M] = &fanout_12M_clk.common.hw,
>> + [CLK_FANOUT_25M] = &fanout_25M_clk.common.hw,
>> + [CLK_FANOUT_27M] = &fanout_27M_clk.common.hw,
>> + [CLK_FANOUT_PCLK] = &fanout_pclk_clk.common.hw,
>> + [CLK_FANOUT0] = &fanout0_clk.common.hw,
>> + [CLK_FANOUT1] = &fanout1_clk.common.hw,
>> + [CLK_FANOUT2] = &fanout2_clk.common.hw,
>> + },
>> +};
>> +
>> +static struct ccu_reset_map sun8i_v853_ccu_resets[] = {
>> + [RST_MBUS] = { 0x540, BIT(30) },
>> + [RST_BUS_DE] = { 0x60c, BIT(16) },
>> + [RST_BUS_G2D] = { 0x63c, BIT(16) },
>> + [RST_BUS_CE] = { 0x68c, BIT(16) | BIT(17)},
>> + [RST_BUS_VE] = { 0x69c, BIT(16) },
>> + [RST_BUS_NPU] = { 0x6ec, BIT(16) },
>> + [RST_BUS_DMA] = { 0x70c, BIT(16) },
>> + [RST_BUS_MSGBOX0] = { 0x71c, BIT(16) },
>> + [RST_BUS_MSGBOX1] = { 0x71c, BIT(17) },
>> + [RST_BUS_SPINLOCK] = { 0x72c, BIT(16) },
>> + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) },
>> + [RST_BUS_DBG] = { 0x78c, BIT(16) },
>> + [RST_BUS_PWM] = { 0x7ac, BIT(16) },
>> + [RST_BUS_DRAM] = { 0x80c, BIT(16) },
>> + [RST_BUS_MMC0] = { 0x84c, BIT(16) },
>> + [RST_BUS_MMC1] = { 0x84c, BIT(17) },
>> + [RST_BUS_MMC2] = { 0x84c, BIT(18) },
>> + [RST_BUS_UART0] = { 0x90c, BIT(16) },
>> + [RST_BUS_UART1] = { 0x90c, BIT(17) },
>> + [RST_BUS_UART2] = { 0x90c, BIT(18) },
>> + [RST_BUS_UART3] = { 0x90c, BIT(19) },
>> + [RST_BUS_I2C0] = { 0x91c, BIT(16) },
>> + [RST_BUS_I2C1] = { 0x91c, BIT(17) },
>> + [RST_BUS_I2C2] = { 0x91c, BIT(18) },
>> + [RST_BUS_I2C3] = { 0x91c, BIT(19) },
>> + [RST_BUS_I2C4] = { 0x91c, BIT(20) },
>> + [RST_BUS_SPI0] = { 0x96c, BIT(16) },
>> + [RST_BUS_SPI1] = { 0x96c, BIT(17) },
>> + [RST_BUS_SPI2] = { 0x96c, BIT(18) },
>> + [RST_BUS_SPI3] = { 0x96c, BIT(19) },
>> + [RST_BUS_SPIF] = { 0x96c, BIT(20) },
>> + [RST_BUS_EMAC] = { 0x97c, BIT(16) },
>> + [RST_BUS_GPADC] = { 0x9ec, BIT(16) },
>> + [RST_BUS_THS] = { 0x9fc, BIT(16) },
>> + [RST_BUS_I2S0] = { 0xa20, BIT(16) },
>> + [RST_BUS_I2S1] = { 0xa20, BIT(17) },
>> + [RST_BUS_DMIC] = { 0xa4c, BIT(16) },
>> + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) },
>> + [RST_USB_PHY] = { 0xa70, BIT(30) },
>> + [RST_BUS_OHCI] = { 0xa8c, BIT(16) },
>> + [RST_BUS_EHCI] = { 0xa8c, BIT(20) },
>> + [RST_BUS_OTG] = { 0xa8c, BIT(24) },
>> + [RST_BUS_DPSS_TOP] = { 0xabc, BIT(16) },
>> + [RST_BUS_MIPI_DSI] = { 0xb4c, BIT(16) },
>> + [RST_BUS_TCON_LCD] = { 0xb7c, BIT(16) },
>> + [RST_BUS_CSI] = { 0xc2c, BIT(16) },
>> + [RST_BUS_WIEGAND] = { 0xc7c, BIT(16) },
>> + [RST_RISCV_SYS_APB] = { 0xd04, BIT(2), CCU_FEATURE_KEY_FIELD },
>> + [RST_RISCV_SOFT] = { 0xd04, BIT(1), CCU_FEATURE_KEY_FIELD },
>> + [RST_RISCV_CFG] = { 0xd0c, BIT(16) }
>> +};
>> +
>> +static const struct sunxi_ccu_desc sun8i_v853_ccu_desc = {
>> + .ccu_clks = sun8i_v853_ccu_clks,
>> + .num_ccu_clks = ARRAY_SIZE(sun8i_v853_ccu_clks),
>> +
>> + .hw_clks = &sun8i_v853_hw_clks,
>> +
>> + .resets = sun8i_v853_ccu_resets,
>> + .num_resets = ARRAY_SIZE(sun8i_v853_ccu_resets),
>> +};
>> +
>> +static const u32 pll_regs[] = {
>> + SUN8I_V853_PLL_CPU_REG,
>> + SUN8I_V853_PLL_DDR_REG,
>> + SUN8I_V853_PLL_PERIPH_REG,
>> + SUN8I_V853_PLL_VIDEO_REG,
>> + SUN8I_V853_PLL_CSI_REG,
>> + SUN8I_V853_PLL_AUDIO_REG,
>> + SUN8I_V853_PLL_NPU_REG,
>> +};
>> +
>> +static int sun8i_v853_ccu_probe(struct platform_device *pdev)
>> +{
>> + void __iomem *reg;
>> + u32 val;
>> + int i, ret;
>> +
>> + reg = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(reg))
>> + return PTR_ERR(reg);
>> +
>> + /* Enable the enable, LDO, and lock bits on all PLLs. */
>> + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
>> + val = readl(reg + pll_regs[i]);
>> + val |= BIT(31) | BIT(30) | BIT(29);
>> + writel(val, reg + pll_regs[i]);
>> + }
>> +
>> + /* Force PLL_CPU factor M to 0. */
>> + val = readl(reg + SUN8I_V853_PLL_CPU_REG);
>> + val &= ~GENMASK(1, 0);
>> + writel(val, reg + SUN8I_V853_PLL_CPU_REG);
>> +
>> + /*
>> + * Force OHCI 12M clock source to 00 (12MHz divided from 48MHz)
>> + *
>> + * This clock mux is still mysterious, and the code just enforces
>> + * it to have a valid clock parent.
>> + */
>> + val = readl(reg + SUN8I_V853_USB_CLK_REG);
>> + val &= ~GENMASK(25, 24);
>> + writel(val, reg + SUN8I_V853_USB_CLK_REG);
>> +
>> + /* Force fanout-27M factor N to 0. */
>> + val = readl(reg + SUN8I_V853_FANOUT_27M_REG);
>> + val &= ~GENMASK(9, 8);
>> + writel(val, reg + SUN8I_V853_FANOUT_27M_REG);
>> +
>> + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_v853_ccu_desc);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id sun8i_v853_ccu_ids[] = {
>> + { .compatible = "allwinner,sun8i-v853-ccu" },
>> + { }
>> +};
>> +
>> +static struct platform_driver sun8i_v853_ccu_driver = {
>> + .probe = sun8i_v853_ccu_probe,
>> + .driver = {
>> + .name = "sun8i-v853-ccu",
>> + .suppress_bind_attrs = true,
>> + .of_match_table = sun8i_v853_ccu_ids,
>> + },
>> +};
>> +module_platform_driver(sun8i_v853_ccu_driver);
>> +
>> +MODULE_IMPORT_NS("SUNXI_CCU");
>> +MODULE_DESCRIPTION("Support for the Allwinner V853 CCU");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v853.h b/drivers/clk/sunxi-ng/ccu-sun8i-v853.h
>> new file mode 100644
>> index 000000000000..f1b2a4d0bcd3
>> --- /dev/null
>> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v853.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2024 Andras Szemzo <szemzo.andras at gmail.com>
>> + */
>> +
>> +#ifndef _CCU_SUN8I_V853_H_
>> +#define _CCU_SUN8I_V853_H_
>> +
>> +#include <dt-bindings/clock/allwinner,sun8i-v853-ccu.h>
>> +#include <dt-bindings/reset/allwinner,sun8i-v853-ccu.h>
>> +
>> +#define CLK_NUMBER (CLK_FANOUT2 + 1)
>> +
>> +#endif
>> 
> 
> 
> 
> 




More information about the linux-riscv mailing list