Message ID | 20201202135409.13683-6-andre.przywara@arm.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | [1/8] clk: sunxi-ng: h6: Fix clock divider range on some clocks | expand |
Hi On Wed, Dec 02, 2020 at 01:54:06PM +0000, Andre Przywara wrote: > While the clocks are fairly similar to the H6, many differ in tiny > details, so a separate clock driver seems indicated. > > Derived from the H6 clock driver, and adjusted according to the manual. > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> The patch itself looks ok, but there's a bunch of checkpatch warning you'll want to fix. Maxime
Dne sreda, 02. december 2020 ob 14:54:06 CET je Andre Przywara napisal(a): > While the clocks are fairly similar to the H6, many differ in tiny > details, so a separate clock driver seems indicated. > > Derived from the H6 clock driver, and adjusted according to the manual. > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > --- > drivers/clk/sunxi-ng/Kconfig | 7 +- > drivers/clk/sunxi-ng/Makefile | 1 + > drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ > drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + > include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ > include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ > 6 files changed, 1376 insertions(+), 1 deletion(-) > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h > create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h > create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h > > diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig > index ce5f5847d5d3..cd46d8853876 100644 > --- a/drivers/clk/sunxi-ng/Kconfig > +++ b/drivers/clk/sunxi-ng/Kconfig > @@ -32,8 +32,13 @@ config SUN50I_H6_CCU > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > +config SUN50I_H616_CCU > + bool "Support for the Allwinner H616 CCU" > + default ARM64 && ARCH_SUNXI > + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > + > config SUN50I_H6_R_CCU > - bool "Support for the Allwinner H6 PRCM CCU" > + bool "Support for the Allwinner H6 and H616 PRCM CCU" > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile > index 3eb5cff40eac..96c324306d97 100644 > --- a/drivers/clk/sunxi-ng/Makefile > +++ b/drivers/clk/sunxi-ng/Makefile > @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o > obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o > obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o > obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o > +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o > obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o > obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o > obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ ccu-sun50i-h616.c > new file mode 100644 > index 000000000000..3fbb258f0354 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > @@ -0,0 +1,1134 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Arm Ltd. > + * Based on the H6 CCU driver, which is: > + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/io.h> > +#include <linux/of_address.h> > +#include <linux/platform_device.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-sun50i-h616.h" > + > +/* > + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However > + * P should only be used for output frequencies lower than 288 MHz. > + * > + * For now we can just model it as a multiplier clock, and force P to /1. > + * > + * The M factor is present in the register's description, but not in the > + * frequency formula, and it's documented as "M is only used for backdoor > + * testing", so it's not modelled and then force to 0. > + */ > +#define SUN50I_H616_PLL_CPUX_REG 0x000 > +static struct ccu_mult pll_cpux_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .common = { > + .reg = 0x000, > + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", > + &ccu_mult_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ > +#define SUN50I_H616_PLL_DDR0_REG 0x010 > +static struct ccu_nkmp pll_ddr0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x010, > + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DDR1_REG 0x018 > +static struct ccu_nkmp pll_ddr1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x018, > + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 > +static struct ccu_nkmp pll_periph0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, > + .common = { > + .reg = 0x020, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 > +static struct ccu_nkmp pll_periph1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, > + .common = { > + .reg = 0x028, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_GPU_REG 0x030 > +static struct ccu_nkmp pll_gpu_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x030, > + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * For Video PLLs, the output divider is described as "used for testing" > + * in the user manual. So it's not modelled and forced to 0. > + */ > +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 > +static struct ccu_nm pll_video0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x040, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 > +static struct ccu_nm pll_video1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x048, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 > +static struct ccu_nm pll_video2_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x050, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VE_REG 0x058 > +static struct ccu_nkmp pll_ve_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x058, > + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DE_REG 0x060 > +static struct ccu_nkmp pll_de_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x060, > + .hw.init = CLK_HW_INIT("pll-de", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * TODO: Determine SDM settings for the audio PLL. The manual suggests > + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b > + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, > + * pattern=0xe001288c for 22.5792 MHz. > + * This clashes with our fixed PLL_POST_DIV_P. > + */ > +#define SUN50I_H616_PLL_AUDIO_REG 0x078 > +static struct ccu_nm pll_audio_hs_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .common = { > + .reg = 0x078, > + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +static const char * const cpux_parents[] = { "osc24M", "osc32k", > + "iosc", "pll-cpux", "pll-periph0" }; > +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, > + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); > +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); > +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); > + > +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", "osc32k", > + "iosc", "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", > + psi_ahb1_ahb2_parents, > + 0x510, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", > + "psi- ahb1-ahb2", > + "pll- periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", > + "pll-ddr0", "pll- ddr1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, > + 0, 3, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_IS_CRITICAL); > + > +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", > + 0x60c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", > + de_parents, > + 0x620, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi-ahb1- ahb2", > + 0x62c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", > + 0x63c, BIT(0), 0); > + > +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, > + 0, 2, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, > + 0, 3, /* M */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", > + 0x67c, BIT(0), 0); > + > +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", > + 0x68c, BIT(0), 0); > + > +static const char * const ve_parents[] = { "pll-ve" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, > + 0, 3, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", > + 0x69c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", > + 0x70c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", > + 0x73c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); > + > +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", > + 0x78c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", > + 0x79c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); > + > +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; > +static struct ccu_div dram_clk = { > + .div = _SUNXI_CCU_DIV(0, 2), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0x800, > + .hw.init = CLK_HW_INIT_PARENTS("dram", > + dram_parents, > + &ccu_div_ops, > + CLK_IS_CRITICAL), > + }, > +}; > + > +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", > + 0x804, BIT(0), 0); > +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", > + 0x804, BIT(1), 0); > +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", > + 0x804, BIT(2), 0); > +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", > + 0x804, BIT(3), 0); > +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", > + 0x804, BIT(5), 0); > +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", > + 0x804, BIT(10), 0); > + > +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", > + 0x80c, BIT(0), CLK_IS_CRITICAL); > + > +static const char * const nand_spi_parents[] = { "osc24M", "pll-periph0", > + "pll-periph1", "pll-periph0-2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); > + > +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); > + > +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0); > +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); > + > +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); > + > +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, > + BIT(31) | BIT(30), 0); > + > +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, BIT(1), 0); > + > +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); > + > +static const char * const audio_parents[] = { "pll-audio-1x", "pll- audio-2x", > + "pll-audio-4x", "pll-audio-hs" }; > +static struct ccu_div spdif_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa20, > + .hw.init = CLK_HW_INIT_PARENTS("spdif", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); > + > +static struct ccu_div dmic_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa40, > + .hw.init = CLK_HW_INIT_PARENTS("dmic", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", > + audio_parents, 0xa50, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", > + audio_parents, 0xa54, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c, > + BIT(0), 0); > + > +static struct ccu_div audio_hub_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa60, > + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, BIT(0), 0); > + > +/* > + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. > + * We will force them to 0 (12M divided from 48M). > + */ > +#define SUN50I_H616_USB0_CLK_REG 0xa70 > +#define SUN50I_H616_USB1_CLK_REG 0xa74 > +#define SUN50I_H616_USB2_CLK_REG 0xa78 > +#define SUN50I_H616_USB3_CLK_REG 0xa7c > + > +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, BIT(29), 0); > + > +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); > +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); > +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, BIT(6), 0); > +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0); > +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); > + > +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, BIT(0), 0); > + > +static struct clk_fixed_factor pll_periph0_4x_clk; > + > +static const char * const hdmi_parents[] = { "pll-video0", "pll-video0-4x", > + "pll-video2", "pll-video2-4x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, BIT(31), 0); > + > +static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; > +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { > + { .index = 1, .div = 36621 }, > +}; > + > +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 > +static struct ccu_mux hdmi_cec_clk = { > + .enable = BIT(31), > + > + .mux = { > + .shift = 24, > + .width = 2, > + > + .fixed_predivs = hdmi_cec_predivs, > + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), > + }, > + > + .common = { > + .reg = 0xb10, > + .features = CCU_FEATURE_VARIABLE_PREDIV, > + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", > + hdmi_cec_parents, > + &ccu_mux_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", > + 0xb5c, BIT(0), 0); > + > +static const char * const tcon_tv0_parents[] = { "pll-video0", > + "pll- video0-4x", > + "pll- video1", > + "pll- video1-4x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", > + tcon_tv0_parents, 0xb80, > + 0, 4, /* M */ > + 8, 2, /* P */ > + 24, 3, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", > + 0xb9c, BIT(0), 0); > + > +static const char * const hdcp_parents[] = { "pll-periph0", "pll-periph1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0); > + > +/* Fixed factor clocks */ > +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); > + > +static const struct clk_hw *clk_parent_pll_audio[] = { > + &pll_audio_hs_clk.common.hw > +}; > + > +/* > + * The divider of pll-audio is fixed to 24 for now, so 24576000 and 22579200 > + * rates can be set exactly in conjunction with sigma-delta modulation. > + */ > +static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", > + clk_parent_pll_audio, > + 96, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", > + clk_parent_pll_audio, > + 48, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", > + clk_parent_pll_audio, > + 24, 1, CLK_SET_RATE_PARENT); > + > +static const struct clk_hw *pll_periph0_parents[] = { > + &pll_periph0_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x", > + pll_periph0_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x", > + pll_periph0_parents, > + 1, 2, 0); > + > +static const struct clk_hw *pll_periph1_parents[] = { > + &pll_periph1_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x", > + pll_periph1_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x", > + pll_periph1_parents, > + 1, 2, 0); > + > +static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x", > + &pll_video0_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x", > + &pll_video1_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video2_4x_clk, "pll-video2-4x", > + &pll_video2_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > + > +static struct ccu_common *sun50i_h616_ccu_clks[] = { > + &pll_cpux_clk.common, > + &pll_ddr0_clk.common, > + &pll_ddr1_clk.common, > + &pll_periph0_clk.common, > + &pll_periph1_clk.common, > + &pll_gpu_clk.common, > + &pll_video0_clk.common, > + &pll_video1_clk.common, > + &pll_video2_clk.common, > + &pll_ve_clk.common, > + &pll_de_clk.common, > + &pll_audio_hs_clk.common, > + &cpux_clk.common, > + &axi_clk.common, > + &cpux_apb_clk.common, > + &psi_ahb1_ahb2_clk.common, > + &ahb3_clk.common, > + &apb1_clk.common, > + &apb2_clk.common, > + &mbus_clk.common, > + &de_clk.common, > + &bus_de_clk.common, > + &deinterlace_clk.common, > + &bus_deinterlace_clk.common, > + &g2d_clk.common, > + &bus_g2d_clk.common, > + &gpu0_clk.common, > + &bus_gpu_clk.common, > + &gpu1_clk.common, > + &ce_clk.common, > + &bus_ce_clk.common, > + &ve_clk.common, > + &bus_ve_clk.common, > + &bus_dma_clk.common, > + &bus_hstimer_clk.common, > + &avs_clk.common, > + &bus_dbg_clk.common, > + &bus_psi_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_ts_clk.common, > + &mbus_nand_clk.common, > + &mbus_g2d_clk.common, > + &bus_dram_clk.common, > + &nand0_clk.common, > + &nand1_clk.common, > + &bus_nand_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_uart4_clk.common, > + &bus_uart5_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, > + &bus_spi0_clk.common, > + &bus_spi1_clk.common, > + &emac_25m_clk.common, > + &bus_emac0_clk.common, > + &bus_emac1_clk.common, > + &ts_clk.common, > + &bus_ts_clk.common, > + &bus_ths_clk.common, > + &spdif_clk.common, > + &bus_spdif_clk.common, > + &dmic_clk.common, > + &bus_dmic_clk.common, > + &audio_codec_1x_clk.common, > + &audio_codec_4x_clk.common, > + &bus_audio_codec_clk.common, > + &audio_hub_clk.common, > + &bus_audio_hub_clk.common, > + &usb_ohci0_clk.common, > + &usb_phy0_clk.common, > + &usb_ohci1_clk.common, > + &usb_phy1_clk.common, > + &usb_ohci2_clk.common, > + &usb_phy2_clk.common, > + &usb_ohci3_clk.common, > + &usb_phy3_clk.common, > + &bus_ohci0_clk.common, > + &bus_ohci1_clk.common, > + &bus_ohci2_clk.common, > + &bus_ohci3_clk.common, > + &bus_ehci0_clk.common, > + &bus_ehci1_clk.common, > + &bus_ehci2_clk.common, > + &bus_ehci3_clk.common, > + &bus_otg_clk.common, > + &bus_keyadc_clk.common, > + &hdmi_clk.common, > + &hdmi_slow_clk.common, > + &hdmi_cec_clk.common, > + &bus_hdmi_clk.common, > + &bus_tcon_top_clk.common, > + &tcon_tv0_clk.common, > + &bus_tcon_tv0_clk.common, > + &hdcp_clk.common, > + &bus_hdcp_clk.common, > +}; > + > +static struct clk_hw_onecell_data sun50i_h616_hw_clks = { > + .hws = { > + [CLK_OSC12M] = &osc12M_clk.hw, > + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, > + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, > + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, > + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, > + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, > + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, > + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, > + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, > + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, > + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, > + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, > + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, > + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, > + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, > + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, > + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, > + [CLK_PLL_VE] = &pll_ve_clk.common.hw, > + [CLK_PLL_DE] = &pll_de_clk.common.hw, > + [CLK_PLL_AUDIO_HS] = &pll_audio_hs_clk.common.hw, > + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.hw, > + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, > + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, > + [CLK_CPUX] = &cpux_clk.common.hw, > + [CLK_AXI] = &axi_clk.common.hw, > + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, > + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw, > + [CLK_AHB3] = &ahb3_clk.common.hw, > + [CLK_APB1] = &apb1_clk.common.hw, > + [CLK_APB2] = &apb2_clk.common.hw, > + [CLK_MBUS] = &mbus_clk.common.hw, > + [CLK_DE] = &de_clk.common.hw, > + [CLK_BUS_DE] = &bus_de_clk.common.hw, > + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, > + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, > + [CLK_G2D] = &g2d_clk.common.hw, > + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, > + [CLK_GPU0] = &gpu0_clk.common.hw, > + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, > + [CLK_GPU1] = &gpu1_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_BUS_DMA] = &bus_dma_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_PSI] = &bus_psi_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_TS] = &mbus_ts_clk.common.hw, > + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, > + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, > + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, > + [CLK_NAND0] = &nand0_clk.common.hw, > + [CLK_NAND1] = &nand1_clk.common.hw, > + [CLK_BUS_NAND] = &bus_nand_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_UART4] = &bus_uart4_clk.common.hw, > + [CLK_BUS_UART5] = &bus_uart5_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_BUS_SPI0] = &bus_spi0_clk.common.hw, > + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, > + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, > + [CLK_BUS_EMAC0] = &bus_emac0_clk.common.hw, > + [CLK_BUS_EMAC1] = &bus_emac1_clk.common.hw, > + [CLK_TS] = &ts_clk.common.hw, > + [CLK_BUS_TS] = &bus_ts_clk.common.hw, > + [CLK_BUS_THS] = &bus_ths_clk.common.hw, > + [CLK_SPDIF] = &spdif_clk.common.hw, > + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, > + [CLK_DMIC] = &dmic_clk.common.hw, > + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, > + [CLK_AUDIO_CODEC_1X] = &audio_codec_1x_clk.common.hw, > + [CLK_AUDIO_CODEC_4X] = &audio_codec_4x_clk.common.hw, > + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw, > + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, > + [CLK_BUS_AUDIO_HUB] = &bus_audio_hub_clk.common.hw, > + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, > + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, > + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, > + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, > + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, > + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, > + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, > + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, > + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, > + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, > + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, > + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, > + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, > + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, > + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, > + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, > + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, > + [CLK_BUS_KEYADC] = &bus_keyadc_clk.common.hw, > + [CLK_HDMI] = &hdmi_clk.common.hw, > + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, > + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, > + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, > + [CLK_BUS_TCON_TOP] = &bus_tcon_top_clk.common.hw, > + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, > + [CLK_BUS_TCON_TV0] = &bus_tcon_tv0_clk.common.hw, > + [CLK_HDCP] = &hdcp_clk.common.hw, > + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, > + }, > + .num = CLK_NUMBER, > +}; > + > +static struct ccu_reset_map sun50i_h616_ccu_resets[] = { > + [RST_MBUS] = { 0x540, BIT(30) }, > + > + [RST_BUS_DE] = { 0x60c, BIT(16) }, > + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, > + [RST_BUS_GPU] = { 0x67c, BIT(16) }, > + [RST_BUS_CE] = { 0x68c, BIT(16) }, > + [RST_BUS_VE] = { 0x69c, BIT(16) }, > + [RST_BUS_DMA] = { 0x70c, BIT(16) }, > + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, > + [RST_BUS_DBG] = { 0x78c, BIT(16) }, > + [RST_BUS_PSI] = { 0x79c, BIT(16) }, > + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, > + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, > + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, > + [RST_BUS_NAND] = { 0x82c, 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_UART4] = { 0x90c, BIT(20) }, > + [RST_BUS_UART5] = { 0x90c, BIT(21) }, > + [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_EMAC0] = { 0x97c, BIT(16) }, > + [RST_BUS_EMAC1] = { 0x97c, BIT(17) }, > + [RST_BUS_TS] = { 0x9bc, BIT(16) }, > + [RST_BUS_THS] = { 0x9fc, BIT(16) }, > + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, > + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, > + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, > + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, > + > + [RST_USB_PHY0] = { 0xa70, BIT(30) }, > + [RST_USB_PHY1] = { 0xa74, BIT(30) }, > + [RST_USB_PHY2] = { 0xa78, BIT(30) }, > + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, > + > + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, > + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, > + [RST_BUS_OHCI2] = { 0xa8c, BIT(18) }, > + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, > + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, > + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, > + [RST_BUS_EHCI2] = { 0xa8c, BIT(22) }, > + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, > + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, > + [RST_BUS_KEYADC] = { 0xa9c, BIT(16) }, > + > + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, > + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, > + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, > + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, > + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, > +}; > + > +static const struct sunxi_ccu_desc sun50i_h616_ccu_desc = { > + .ccu_clks = sun50i_h616_ccu_clks, > + .num_ccu_clks = ARRAY_SIZE(sun50i_h616_ccu_clks), > + > + .hw_clks = &sun50i_h616_hw_clks, > + > + .resets = sun50i_h616_ccu_resets, > + .num_resets = ARRAY_SIZE(sun50i_h616_ccu_resets), > +}; > + > +static const u32 pll_regs[] = { > + SUN50I_H616_PLL_CPUX_REG, > + SUN50I_H616_PLL_DDR0_REG, > + SUN50I_H616_PLL_DDR1_REG, > + SUN50I_H616_PLL_PERIPH0_REG, > + SUN50I_H616_PLL_PERIPH1_REG, > + SUN50I_H616_PLL_GPU_REG, > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > + SUN50I_H616_PLL_VE_REG, > + SUN50I_H616_PLL_DE_REG, > + SUN50I_H616_PLL_AUDIO_REG, > +}; > + > +static const u32 pll_video_regs[] = { > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > +}; > + > +static const u32 usb2_clk_regs[] = { > + SUN50I_H616_USB0_CLK_REG, > + SUN50I_H616_USB1_CLK_REG, > + SUN50I_H616_USB2_CLK_REG, > + SUN50I_H616_USB3_CLK_REG, > +}; > + > +static int sun50i_h616_ccu_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + void __iomem *reg; > + u32 val; > + int i; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + reg = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(reg)) > + return PTR_ERR(reg); > + > + /* Enable the lock bits on all PLLs */ > + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { > + val = readl(reg + pll_regs[i]); > + val |= BIT(29); You should also add BIT(27) here. It enables PLL output (new functionality in H616). Without this only clocks which are child of PLL_CPUX and PLL_PERIPH0 would work (set up by U-Boot). I'm pretty sure that's not intended usage but until we know better, it's ok imo. > + writel(val, reg + pll_regs[i]); > + } > + > + /* > + * Force the output divider of video PLLs to 0. > + * > + * See the comment before pll-video0 definition for the reason. > + */ > + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { > + val = readl(reg + pll_video_regs[i]); > + val &= ~BIT(0); > + writel(val, reg + pll_video_regs[i]); > + } > + > + /* > + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) > + * > + * This clock mux is still mysterious, and the code just enforces > + * it to have a valid clock parent. > + */ > + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { > + val = readl(reg + usb2_clk_regs[i]); > + val &= ~GENMASK(25, 24); > + writel (val, reg + usb2_clk_regs[i]); > + } > + > + /* > + * Force the post-divider of pll-audio to 12 and the output divider > + * of it to 2, so 24576000 and 22579200 rates can be set exactly. > + */ > + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); > + val &= ~(GENMASK(21, 16) | BIT(0)); > + writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG); > + > + /* > + * First clock parent (osc32K) is unusable for CEC. But since there > + * is no good way to force parent switch (both run with same frequency), > + * just set second clock parent here. > + */ > + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + val |= BIT(24); > + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + > + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h616_ccu_desc); > +} > + > +static const struct of_device_id sun50i_h616_ccu_ids[] = { > + { .compatible = "allwinner,sun50i-h616-ccu", > + .data = &sun50i_h616_ccu_desc }, > + { } > +}; > + > +static struct platform_driver sun50i_h616_ccu_driver = { > + .probe = sun50i_h616_ccu_probe, > + .driver = { > + .name = "sun50i-h616-ccu", > + .of_match_table = sun50i_h616_ccu_ids, > + }, > +}; > +builtin_platform_driver(sun50i_h616_ccu_driver); Please use CLK_OF_DECLARE() instead. That way clocks will be initialized earlier and it will be actually possible to register both timer peripherals (once DT nodes are added). If pdev or dev is ever needed, two stage initialization can be made later. Best regards, Jernej > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h b/drivers/clk/sunxi-ng/ ccu-sun50i-h616.h > new file mode 100644 > index 000000000000..da8f0b1206f9 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > @@ -0,0 +1,58 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright 2020 Arm Ltd. > + */ > + > +#ifndef _CCU_SUN50I_H616_H_ > +#define _CCU_SUN50I_H616_H_ > + > +#include <dt-bindings/clock/sun50i-h616-ccu.h> > +#include <dt-bindings/reset/sun50i-h616-ccu.h> > + > +#define CLK_OSC12M 0 > +#define CLK_PLL_CPUX 1 > +#define CLK_PLL_DDR0 2 > +#define CLK_PLL_DDR1 3 > + > +/* PLL_PERIPH0 exported for PRCM */ > + > +#define CLK_PLL_PERIPH0_2X 5 > +#define CLK_PLL_PERIPH0_4X 6 > +#define CLK_PLL_PERIPH1 7 > +#define CLK_PLL_PERIPH1_2X 8 > +#define CLK_PLL_PERIPH1_4X 9 > +#define CLK_PLL_GPU 10 > +#define CLK_PLL_VIDEO0 11 > +#define CLK_PLL_VIDEO0_4X 12 > +#define CLK_PLL_VIDEO1 13 > +#define CLK_PLL_VIDEO1_4X 14 > +#define CLK_PLL_VIDEO2 15 > +#define CLK_PLL_VIDEO2_4X 16 > +#define CLK_PLL_VE 17 > +#define CLK_PLL_DE 18 > +#define CLK_PLL_AUDIO_HS 19 > +#define CLK_PLL_AUDIO_1X 20 > +#define CLK_PLL_AUDIO_2X 21 > +#define CLK_PLL_AUDIO_4X 22 > + > +/* CPUX clock exported for DVFS */ > + > +#define CLK_AXI 24 > +#define CLK_CPUX_APB 25 > +#define CLK_PSI_AHB1_AHB2 26 > +#define CLK_AHB3 27 > + > +/* APB1 clock exported for PIO */ > + > +#define CLK_APB2 29 > +#define CLK_MBUS 30 > + > +/* All module clocks and bus gates are exported except DRAM */ > + > +#define CLK_DRAM 51 > + > +#define CLK_BUS_DRAM 58 > + > +#define CLK_NUMBER (CLK_BUS_HDCP + 1) > + > +#endif /* _CCU_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h b/include/dt- bindings/clock/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..a9cc8844e3a9 > --- /dev/null > +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h > @@ -0,0 +1,110 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2020 Arm Ltd. > + */ > + > +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ > +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ > + > +#define CLK_PLL_PERIPH0 4 > + > +#define CLK_CPUX 23 > + > +#define CLK_APB1 28 > + > +#define CLK_DE 31 > +#define CLK_BUS_DE 32 > +#define CLK_DEINTERLACE 33 > +#define CLK_BUS_DEINTERLACE 34 > +#define CLK_G2D 35 > +#define CLK_BUS_G2D 36 > +#define CLK_GPU0 37 > +#define CLK_BUS_GPU 38 > +#define CLK_GPU1 39 > +#define CLK_CE 40 > +#define CLK_BUS_CE 41 > +#define CLK_VE 42 > +#define CLK_BUS_VE 43 > +#define CLK_BUS_DMA 44 > +#define CLK_BUS_HSTIMER 45 > +#define CLK_AVS 46 > +#define CLK_BUS_DBG 47 > +#define CLK_BUS_PSI 48 > +#define CLK_BUS_PWM 49 > +#define CLK_BUS_IOMMU 50 > + > +#define CLK_MBUS_DMA 52 > +#define CLK_MBUS_VE 53 > +#define CLK_MBUS_CE 54 > +#define CLK_MBUS_TS 55 > +#define CLK_MBUS_NAND 56 > +#define CLK_MBUS_G2D 57 > + > +#define CLK_NAND0 59 > +#define CLK_NAND1 60 > +#define CLK_BUS_NAND 61 > +#define CLK_MMC0 62 > +#define CLK_MMC1 63 > +#define CLK_MMC2 64 > +#define CLK_BUS_MMC0 65 > +#define CLK_BUS_MMC1 66 > +#define CLK_BUS_MMC2 67 > +#define CLK_BUS_UART0 68 > +#define CLK_BUS_UART1 69 > +#define CLK_BUS_UART2 70 > +#define CLK_BUS_UART3 71 > +#define CLK_BUS_UART4 72 > +#define CLK_BUS_UART5 73 > +#define CLK_BUS_I2C0 74 > +#define CLK_BUS_I2C1 75 > +#define CLK_BUS_I2C2 76 > +#define CLK_BUS_I2C3 77 > +#define CLK_BUS_I2C4 78 > +#define CLK_SPI0 79 > +#define CLK_SPI1 80 > +#define CLK_BUS_SPI0 81 > +#define CLK_BUS_SPI1 82 > +#define CLK_EMAC_25M 83 > +#define CLK_BUS_EMAC0 84 > +#define CLK_BUS_EMAC1 85 > +#define CLK_TS 86 > +#define CLK_BUS_TS 87 > +#define CLK_BUS_THS 88 > +#define CLK_SPDIF 89 > +#define CLK_BUS_SPDIF 90 > +#define CLK_DMIC 91 > +#define CLK_BUS_DMIC 92 > +#define CLK_AUDIO_CODEC_1X 93 > +#define CLK_AUDIO_CODEC_4X 94 > +#define CLK_BUS_AUDIO_CODEC 95 > +#define CLK_AUDIO_HUB 96 > +#define CLK_BUS_AUDIO_HUB 97 > +#define CLK_USB_OHCI0 98 > +#define CLK_USB_PHY0 99 > +#define CLK_USB_OHCI1 100 > +#define CLK_USB_PHY1 101 > +#define CLK_USB_OHCI2 102 > +#define CLK_USB_PHY2 103 > +#define CLK_USB_OHCI3 104 > +#define CLK_USB_PHY3 105 > +#define CLK_BUS_OHCI0 106 > +#define CLK_BUS_OHCI1 107 > +#define CLK_BUS_OHCI2 108 > +#define CLK_BUS_OHCI3 109 > +#define CLK_BUS_EHCI0 110 > +#define CLK_BUS_EHCI1 111 > +#define CLK_BUS_EHCI2 112 > +#define CLK_BUS_EHCI3 113 > +#define CLK_BUS_OTG 114 > +#define CLK_BUS_KEYADC 115 > +#define CLK_HDMI 116 > +#define CLK_HDMI_SLOW 117 > +#define CLK_HDMI_CEC 118 > +#define CLK_BUS_HDMI 119 > +#define CLK_BUS_TCON_TOP 120 > +#define CLK_TCON_TV0 121 > +#define CLK_BUS_TCON_TV0 122 > +#define CLK_HDCP 123 > +#define CLK_BUS_HDCP 124 > + > +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h b/include/dt- bindings/reset/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..1c992cfbbbab > --- /dev/null > +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h > @@ -0,0 +1,67 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ > +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ > + > +#define RST_MBUS 0 > +#define RST_BUS_DE 1 > +#define RST_BUS_DEINTERLACE 2 > +#define RST_BUS_GPU 3 > +#define RST_BUS_CE 4 > +#define RST_BUS_VE 5 > +#define RST_BUS_DMA 6 > +#define RST_BUS_HSTIMER 7 > +#define RST_BUS_DBG 8 > +#define RST_BUS_PSI 9 > +#define RST_BUS_PWM 10 > +#define RST_BUS_IOMMU 11 > +#define RST_BUS_DRAM 12 > +#define RST_BUS_NAND 13 > +#define RST_BUS_MMC0 14 > +#define RST_BUS_MMC1 15 > +#define RST_BUS_MMC2 16 > +#define RST_BUS_UART0 17 > +#define RST_BUS_UART1 18 > +#define RST_BUS_UART2 19 > +#define RST_BUS_UART3 20 > +#define RST_BUS_UART4 21 > +#define RST_BUS_UART5 22 > +#define RST_BUS_I2C0 23 > +#define RST_BUS_I2C1 24 > +#define RST_BUS_I2C2 25 > +#define RST_BUS_I2C3 26 > +#define RST_BUS_I2C4 27 > +#define RST_BUS_SPI0 28 > +#define RST_BUS_SPI1 29 > +#define RST_BUS_EMAC0 30 > +#define RST_BUS_EMAC1 31 > +#define RST_BUS_TS 32 > +#define RST_BUS_THS 33 > +#define RST_BUS_SPDIF 34 > +#define RST_BUS_DMIC 35 > +#define RST_BUS_AUDIO_CODEC 36 > +#define RST_BUS_AUDIO_HUB 37 > +#define RST_USB_PHY0 38 > +#define RST_USB_PHY1 39 > +#define RST_USB_PHY2 40 > +#define RST_USB_PHY3 41 > +#define RST_BUS_OHCI0 42 > +#define RST_BUS_OHCI1 43 > +#define RST_BUS_OHCI2 44 > +#define RST_BUS_OHCI3 45 > +#define RST_BUS_EHCI0 46 > +#define RST_BUS_EHCI1 47 > +#define RST_BUS_EHCI2 48 > +#define RST_BUS_EHCI3 49 > +#define RST_BUS_OTG 50 > +#define RST_BUS_HDMI 51 > +#define RST_BUS_HDMI_SUB 52 > +#define RST_BUS_TCON_TOP 53 > +#define RST_BUS_TCON_TV0 54 > +#define RST_BUS_HDCP 55 > +#define RST_BUS_KEYADC 56 > + > +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ > -- > 2.17.5 > > >
On 02/12/2020 21:03, Jernej Škrabec wrote: > Dne sreda, 02. december 2020 ob 14:54:06 CET je Andre Przywara napisal(a): >> While the clocks are fairly similar to the H6, many differ in tiny >> details, so a separate clock driver seems indicated. >> >> Derived from the H6 clock driver, and adjusted according to the manual. >> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com> >> --- >> drivers/clk/sunxi-ng/Kconfig | 7 +- >> drivers/clk/sunxi-ng/Makefile | 1 + >> drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ >> drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + >> include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ >> include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ >> 6 files changed, 1376 insertions(+), 1 deletion(-) >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h >> create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h >> >> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig >> index ce5f5847d5d3..cd46d8853876 100644 >> --- a/drivers/clk/sunxi-ng/Kconfig >> +++ b/drivers/clk/sunxi-ng/Kconfig .... >> +static int sun50i_h616_ccu_probe(struct platform_device *pdev) >> +{ >> + struct resource *res; >> + void __iomem *reg; >> + u32 val; >> + int i; >> + >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + reg = devm_ioremap_resource(&pdev->dev, res); >> + if (IS_ERR(reg)) >> + return PTR_ERR(reg); >> + >> + /* Enable the lock bits on all PLLs */ >> + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { >> + val = readl(reg + pll_regs[i]); >> + val |= BIT(29); > > You should also add BIT(27) here. It enables PLL output (new functionality in > H616). Without this only clocks which are child of PLL_CPUX and PLL_PERIPH0 > would work (set up by U-Boot). I'm pretty sure that's not intended usage but > until we know better, it's ok imo. Ah right, the output enable bit. I was wondering if the A100 solution would better here: use bit 27 as the .enable value, and actually enable (bit31) all PLLs here. Or we add another field, maybe a flag, to allow the kernel to decide which bit to use. Clement suggested something like that on IRC. But for now I can surely just set bit 27 here as well. >> + writel(val, reg + pll_regs[i]); >> + } >> + >> + /* >> + * Force the output divider of video PLLs to 0. >> + * >> + * See the comment before pll-video0 definition for the reason. >> + */ >> + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { >> + val = readl(reg + pll_video_regs[i]); >> + val &= ~BIT(0); >> + writel(val, reg + pll_video_regs[i]); >> + } >> + >> + /* >> + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) >> + * >> + * This clock mux is still mysterious, and the code just enforces >> + * it to have a valid clock parent. >> + */ >> + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { >> + val = readl(reg + usb2_clk_regs[i]); >> + val &= ~GENMASK(25, 24); >> + writel (val, reg + usb2_clk_regs[i]); >> + } >> + >> + /* >> + * Force the post-divider of pll-audio to 12 and the output divider >> + * of it to 2, so 24576000 and 22579200 rates can be set exactly. >> + */ >> + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); >> + val &= ~(GENMASK(21, 16) | BIT(0)); >> + writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG); >> + >> + /* >> + * First clock parent (osc32K) is unusable for CEC. But since there >> + * is no good way to force parent switch (both run with same frequency), >> + * just set second clock parent here. >> + */ >> + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); >> + val |= BIT(24); >> + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); >> + >> + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h616_ccu_desc); >> +} >> + >> +static const struct of_device_id sun50i_h616_ccu_ids[] = { >> + { .compatible = "allwinner,sun50i-h616-ccu", >> + .data = &sun50i_h616_ccu_desc }, >> + { } >> +}; >> + >> +static struct platform_driver sun50i_h616_ccu_driver = { >> + .probe = sun50i_h616_ccu_probe, >> + .driver = { >> + .name = "sun50i-h616-ccu", >> + .of_match_table = sun50i_h616_ccu_ids, >> + }, >> +}; >> +builtin_platform_driver(sun50i_h616_ccu_driver); > > Please use CLK_OF_DECLARE() instead. That way clocks will be initialized > earlier and it will be actually possible to register both timer peripherals > (once DT nodes are added). If pdev or dev is ever needed, two stage > initialization can be made later. Sure, will do. Thanks for having a look! Andre > > Best regards, > Jernej > >> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> new file mode 100644 >> index 000000000000..da8f0b1206f9 >> --- /dev/null >> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> @@ -0,0 +1,58 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright 2020 Arm Ltd. >> + */ >> + >> +#ifndef _CCU_SUN50I_H616_H_ >> +#define _CCU_SUN50I_H616_H_ >> + >> +#include <dt-bindings/clock/sun50i-h616-ccu.h> >> +#include <dt-bindings/reset/sun50i-h616-ccu.h> >> + >> +#define CLK_OSC12M 0 >> +#define CLK_PLL_CPUX 1 >> +#define CLK_PLL_DDR0 2 >> +#define CLK_PLL_DDR1 3 >> + >> +/* PLL_PERIPH0 exported for PRCM */ >> + >> +#define CLK_PLL_PERIPH0_2X 5 >> +#define CLK_PLL_PERIPH0_4X 6 >> +#define CLK_PLL_PERIPH1 7 >> +#define CLK_PLL_PERIPH1_2X 8 >> +#define CLK_PLL_PERIPH1_4X 9 >> +#define CLK_PLL_GPU 10 >> +#define CLK_PLL_VIDEO0 11 >> +#define CLK_PLL_VIDEO0_4X 12 >> +#define CLK_PLL_VIDEO1 13 >> +#define CLK_PLL_VIDEO1_4X 14 >> +#define CLK_PLL_VIDEO2 15 >> +#define CLK_PLL_VIDEO2_4X 16 >> +#define CLK_PLL_VE 17 >> +#define CLK_PLL_DE 18 >> +#define CLK_PLL_AUDIO_HS 19 >> +#define CLK_PLL_AUDIO_1X 20 >> +#define CLK_PLL_AUDIO_2X 21 >> +#define CLK_PLL_AUDIO_4X 22 >> + >> +/* CPUX clock exported for DVFS */ >> + >> +#define CLK_AXI 24 >> +#define CLK_CPUX_APB 25 >> +#define CLK_PSI_AHB1_AHB2 26 >> +#define CLK_AHB3 27 >> + >> +/* APB1 clock exported for PIO */ >> + >> +#define CLK_APB2 29 >> +#define CLK_MBUS 30 >> + >> +/* All module clocks and bus gates are exported except DRAM */ >> + >> +#define CLK_DRAM 51 >> + >> +#define CLK_BUS_DRAM 58 >> + >> +#define CLK_NUMBER (CLK_BUS_HDCP + 1) >> + >> +#endif /* _CCU_SUN50I_H616_H_ */ >> diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h b/include/dt-bindings/clock/sun50i-h616-ccu.h >> new file mode 100644 >> index 000000000000..a9cc8844e3a9 >> --- /dev/null >> +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h >> @@ -0,0 +1,110 @@ >> +// SPDX-License-Identifier: (GPL-2.0+ or MIT) >> +/* >> + * Copyright (C) 2020 Arm Ltd. >> + */ >> + >> +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ >> +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ >> + >> +#define CLK_PLL_PERIPH0 4 >> + >> +#define CLK_CPUX 23 >> + >> +#define CLK_APB1 28 >> + >> +#define CLK_DE 31 >> +#define CLK_BUS_DE 32 >> +#define CLK_DEINTERLACE 33 >> +#define CLK_BUS_DEINTERLACE 34 >> +#define CLK_G2D 35 >> +#define CLK_BUS_G2D 36 >> +#define CLK_GPU0 37 >> +#define CLK_BUS_GPU 38 >> +#define CLK_GPU1 39 >> +#define CLK_CE 40 >> +#define CLK_BUS_CE 41 >> +#define CLK_VE 42 >> +#define CLK_BUS_VE 43 >> +#define CLK_BUS_DMA 44 >> +#define CLK_BUS_HSTIMER 45 >> +#define CLK_AVS 46 >> +#define CLK_BUS_DBG 47 >> +#define CLK_BUS_PSI 48 >> +#define CLK_BUS_PWM 49 >> +#define CLK_BUS_IOMMU 50 >> + >> +#define CLK_MBUS_DMA 52 >> +#define CLK_MBUS_VE 53 >> +#define CLK_MBUS_CE 54 >> +#define CLK_MBUS_TS 55 >> +#define CLK_MBUS_NAND 56 >> +#define CLK_MBUS_G2D 57 >> + >> +#define CLK_NAND0 59 >> +#define CLK_NAND1 60 >> +#define CLK_BUS_NAND 61 >> +#define CLK_MMC0 62 >> +#define CLK_MMC1 63 >> +#define CLK_MMC2 64 >> +#define CLK_BUS_MMC0 65 >> +#define CLK_BUS_MMC1 66 >> +#define CLK_BUS_MMC2 67 >> +#define CLK_BUS_UART0 68 >> +#define CLK_BUS_UART1 69 >> +#define CLK_BUS_UART2 70 >> +#define CLK_BUS_UART3 71 >> +#define CLK_BUS_UART4 72 >> +#define CLK_BUS_UART5 73 >> +#define CLK_BUS_I2C0 74 >> +#define CLK_BUS_I2C1 75 >> +#define CLK_BUS_I2C2 76 >> +#define CLK_BUS_I2C3 77 >> +#define CLK_BUS_I2C4 78 >> +#define CLK_SPI0 79 >> +#define CLK_SPI1 80 >> +#define CLK_BUS_SPI0 81 >> +#define CLK_BUS_SPI1 82 >> +#define CLK_EMAC_25M 83 >> +#define CLK_BUS_EMAC0 84 >> +#define CLK_BUS_EMAC1 85 >> +#define CLK_TS 86 >> +#define CLK_BUS_TS 87 >> +#define CLK_BUS_THS 88 >> +#define CLK_SPDIF 89 >> +#define CLK_BUS_SPDIF 90 >> +#define CLK_DMIC 91 >> +#define CLK_BUS_DMIC 92 >> +#define CLK_AUDIO_CODEC_1X 93 >> +#define CLK_AUDIO_CODEC_4X 94 >> +#define CLK_BUS_AUDIO_CODEC 95 >> +#define CLK_AUDIO_HUB 96 >> +#define CLK_BUS_AUDIO_HUB 97 >> +#define CLK_USB_OHCI0 98 >> +#define CLK_USB_PHY0 99 >> +#define CLK_USB_OHCI1 100 >> +#define CLK_USB_PHY1 101 >> +#define CLK_USB_OHCI2 102 >> +#define CLK_USB_PHY2 103 >> +#define CLK_USB_OHCI3 104 >> +#define CLK_USB_PHY3 105 >> +#define CLK_BUS_OHCI0 106 >> +#define CLK_BUS_OHCI1 107 >> +#define CLK_BUS_OHCI2 108 >> +#define CLK_BUS_OHCI3 109 >> +#define CLK_BUS_EHCI0 110 >> +#define CLK_BUS_EHCI1 111 >> +#define CLK_BUS_EHCI2 112 >> +#define CLK_BUS_EHCI3 113 >> +#define CLK_BUS_OTG 114 >> +#define CLK_BUS_KEYADC 115 >> +#define CLK_HDMI 116 >> +#define CLK_HDMI_SLOW 117 >> +#define CLK_HDMI_CEC 118 >> +#define CLK_BUS_HDMI 119 >> +#define CLK_BUS_TCON_TOP 120 >> +#define CLK_TCON_TV0 121 >> +#define CLK_BUS_TCON_TV0 122 >> +#define CLK_HDCP 123 >> +#define CLK_BUS_HDCP 124 >> + >> +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ >> diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h b/include/dt-bindings/reset/sun50i-h616-ccu.h >> new file mode 100644 >> index 000000000000..1c992cfbbbab >> --- /dev/null >> +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h >> @@ -0,0 +1,67 @@ >> +// SPDX-License-Identifier: (GPL-2.0+ or MIT) >> +/* >> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> >> + */ >> + >> +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ >> +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ >> + >> +#define RST_MBUS 0 >> +#define RST_BUS_DE 1 >> +#define RST_BUS_DEINTERLACE 2 >> +#define RST_BUS_GPU 3 >> +#define RST_BUS_CE 4 >> +#define RST_BUS_VE 5 >> +#define RST_BUS_DMA 6 >> +#define RST_BUS_HSTIMER 7 >> +#define RST_BUS_DBG 8 >> +#define RST_BUS_PSI 9 >> +#define RST_BUS_PWM 10 >> +#define RST_BUS_IOMMU 11 >> +#define RST_BUS_DRAM 12 >> +#define RST_BUS_NAND 13 >> +#define RST_BUS_MMC0 14 >> +#define RST_BUS_MMC1 15 >> +#define RST_BUS_MMC2 16 >> +#define RST_BUS_UART0 17 >> +#define RST_BUS_UART1 18 >> +#define RST_BUS_UART2 19 >> +#define RST_BUS_UART3 20 >> +#define RST_BUS_UART4 21 >> +#define RST_BUS_UART5 22 >> +#define RST_BUS_I2C0 23 >> +#define RST_BUS_I2C1 24 >> +#define RST_BUS_I2C2 25 >> +#define RST_BUS_I2C3 26 >> +#define RST_BUS_I2C4 27 >> +#define RST_BUS_SPI0 28 >> +#define RST_BUS_SPI1 29 >> +#define RST_BUS_EMAC0 30 >> +#define RST_BUS_EMAC1 31 >> +#define RST_BUS_TS 32 >> +#define RST_BUS_THS 33 >> +#define RST_BUS_SPDIF 34 >> +#define RST_BUS_DMIC 35 >> +#define RST_BUS_AUDIO_CODEC 36 >> +#define RST_BUS_AUDIO_HUB 37 >> +#define RST_USB_PHY0 38 >> +#define RST_USB_PHY1 39 >> +#define RST_USB_PHY2 40 >> +#define RST_USB_PHY3 41 >> +#define RST_BUS_OHCI0 42 >> +#define RST_BUS_OHCI1 43 >> +#define RST_BUS_OHCI2 44 >> +#define RST_BUS_OHCI3 45 >> +#define RST_BUS_EHCI0 46 >> +#define RST_BUS_EHCI1 47 >> +#define RST_BUS_EHCI2 48 >> +#define RST_BUS_EHCI3 49 >> +#define RST_BUS_OTG 50 >> +#define RST_BUS_HDMI 51 >> +#define RST_BUS_HDMI_SUB 52 >> +#define RST_BUS_TCON_TOP 53 >> +#define RST_BUS_TCON_TV0 54 >> +#define RST_BUS_HDCP 55 >> +#define RST_BUS_KEYADC 56 >> + >> +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ >> -- >> 2.17.5 >> >> >> > >
在 2020-12-02星期三的 23:06 +0000,André Przywara写道: > On 02/12/2020 21:03, Jernej Škrabec wrote: > > Dne sreda, 02. december 2020 ob 14:54:06 CET je Andre Przywara > > napisal(a): > > > While the clocks are fairly similar to the H6, many differ in > > > tiny > > > details, so a separate clock driver seems indicated. > > > > > > Derived from the H6 clock driver, and adjusted according to the > > > manual. > > > > > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > > > --- > > > drivers/clk/sunxi-ng/Kconfig | 7 +- > > > drivers/clk/sunxi-ng/Makefile | 1 + > > > drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 > > > +++++++++++++++++++ > > > drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + > > > include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ > > > include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ > > > 6 files changed, 1376 insertions(+), 1 deletion(-) > > > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c > > > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h > > > create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h > > > create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h > > > > > > diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi- > > > ng/Kconfig > > > index ce5f5847d5d3..cd46d8853876 100644 > > > --- a/drivers/clk/sunxi-ng/Kconfig > > > +++ b/drivers/clk/sunxi-ng/Kconfig > > .... > > > > +static int sun50i_h616_ccu_probe(struct platform_device *pdev) > > > +{ > > > + struct resource *res; > > > + void __iomem *reg; > > > + u32 val; > > > + int i; > > > + > > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > > + reg = devm_ioremap_resource(&pdev->dev, res); > > > + if (IS_ERR(reg)) > > > + return PTR_ERR(reg); > > > + > > > + /* Enable the lock bits on all PLLs */ > > > + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { > > > + val = readl(reg + pll_regs[i]); > > > + val |= BIT(29); > > > > You should also add BIT(27) here. It enables PLL output (new > > functionality in > > H616). Without this only clocks which are child of PLL_CPUX and > > PLL_PERIPH0 > > would work (set up by U-Boot). I'm pretty sure that's not intended > > usage but > > until we know better, it's ok imo. > > Ah right, the output enable bit. I was wondering if the A100 solution > would better here: use bit 27 as the .enable value, and actually > enable Why not .enable = BIT(27) | BIT(31) ? > (bit31) all PLLs here. > Or we add another field, maybe a flag, to allow the kernel to decide > which bit to use. Clement suggested something like that on IRC. > But for now I can surely just set bit 27 here as well. > > > > + writel(val, reg + pll_regs[i]); > > > + } > > > + > > > + /* > > > + * Force the output divider of video PLLs to 0. > > > + * > > > + * See the comment before pll-video0 definition for the reason. > > > + */ > > > + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { > > > + val = readl(reg + pll_video_regs[i]); > > > + val &= ~BIT(0); > > > + writel(val, reg + pll_video_regs[i]); > > > + } > > > + > > > + /* > > > + * Force OHCI 12M clock sources to 00 (12MHz divided from > > > 48MHz) > > > + * > > > + * This clock mux is still mysterious, and the code just > > > enforces > > > + * it to have a valid clock parent. > > > + */ > > > + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { > > > + val = readl(reg + usb2_clk_regs[i]); > > > + val &= ~GENMASK(25, 24); > > > + writel (val, reg + usb2_clk_regs[i]); > > > + } > > > + > > > + /* > > > + * Force the post-divider of pll-audio to 12 and the output > > > divider > > > + * of it to 2, so 24576000 and 22579200 rates can be set > > > exactly. > > > + */ > > > + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); > > > + val &= ~(GENMASK(21, 16) | BIT(0)); > > > + writel(val | (11 << 16) | BIT(0), reg + > > > SUN50I_H616_PLL_AUDIO_REG); > > > + > > > + /* > > > + * First clock parent (osc32K) is unusable for CEC. But since > > > there > > > + * is no good way to force parent switch (both run with same > > > frequency), > > > + * just set second clock parent here. > > > + */ > > > + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); > > > + val |= BIT(24); > > > + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); > > > + > > > + return sunxi_ccu_probe(pdev->dev.of_node, reg, > > > &sun50i_h616_ccu_desc); > > > +} > > > + > > > +static const struct of_device_id sun50i_h616_ccu_ids[] = { > > > + { .compatible = "allwinner,sun50i-h616-ccu", > > > + .data = &sun50i_h616_ccu_desc }, > > > + { } > > > +}; > > > + > > > +static struct platform_driver sun50i_h616_ccu_driver = { > > > + .probe = sun50i_h616_ccu_probe, > > > + .driver = { > > > + .name = "sun50i-h616-ccu", > > > + .of_match_table = sun50i_h616_ccu_ids, > > > + }, > > > +}; > > > +builtin_platform_driver(sun50i_h616_ccu_driver); > > > > Please use CLK_OF_DECLARE() instead. That way clocks will be > > initialized > > earlier and it will be actually possible to register both timer > > peripherals > > (once DT nodes are added). If pdev or dev is ever needed, two > > stage > > initialization can be made later. > > Sure, will do. > > Thanks for having a look! > > Andre > > > Best regards, > > Jernej > > > > > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > > > b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > > > new file mode 100644 > > > index 000000000000..da8f0b1206f9 > > > --- /dev/null > > > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > > > @@ -0,0 +1,58 @@ > > > +/* SPDX-License-Identifier: GPL-2.0 */ > > > +/* > > > + * Copyright 2020 Arm Ltd. > > > + */ > > > + > > > +#ifndef _CCU_SUN50I_H616_H_ > > > +#define _CCU_SUN50I_H616_H_ > > > + > > > +#include <dt-bindings/clock/sun50i-h616-ccu.h> > > > +#include <dt-bindings/reset/sun50i-h616-ccu.h> > > > + > > > +#define CLK_OSC12M 0 > > > +#define CLK_PLL_CPUX 1 > > > +#define CLK_PLL_DDR0 2 > > > +#define CLK_PLL_DDR1 3 > > > + > > > +/* PLL_PERIPH0 exported for PRCM */ > > > + > > > +#define CLK_PLL_PERIPH0_2X 5 > > > +#define CLK_PLL_PERIPH0_4X 6 > > > +#define CLK_PLL_PERIPH1 7 > > > +#define CLK_PLL_PERIPH1_2X 8 > > > +#define CLK_PLL_PERIPH1_4X 9 > > > +#define CLK_PLL_GPU 10 > > > +#define CLK_PLL_VIDEO0 11 > > > +#define CLK_PLL_VIDEO0_4X 12 > > > +#define CLK_PLL_VIDEO1 13 > > > +#define CLK_PLL_VIDEO1_4X 14 > > > +#define CLK_PLL_VIDEO2 15 > > > +#define CLK_PLL_VIDEO2_4X 16 > > > +#define CLK_PLL_VE 17 > > > +#define CLK_PLL_DE 18 > > > +#define CLK_PLL_AUDIO_HS 19 > > > +#define CLK_PLL_AUDIO_1X 20 > > > +#define CLK_PLL_AUDIO_2X 21 > > > +#define CLK_PLL_AUDIO_4X 22 > > > + > > > +/* CPUX clock exported for DVFS */ > > > + > > > +#define CLK_AXI 24 > > > +#define CLK_CPUX_APB 25 > > > +#define CLK_PSI_AHB1_AHB2 26 > > > +#define CLK_AHB3 27 > > > + > > > +/* APB1 clock exported for PIO */ > > > + > > > +#define CLK_APB2 29 > > > +#define CLK_MBUS 30 > > > + > > > +/* All module clocks and bus gates are exported except DRAM */ > > > + > > > +#define CLK_DRAM 51 > > > + > > > +#define CLK_BUS_DRAM 58 > > > + > > > +#define CLK_NUMBER (CLK_BUS_HDCP + 1) > > > + > > > +#endif /* _CCU_SUN50I_H616_H_ */ > > > diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h > > > b/include/dt-bindings/clock/sun50i-h616-ccu.h > > > new file mode 100644 > > > index 000000000000..a9cc8844e3a9 > > > --- /dev/null > > > +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h > > > @@ -0,0 +1,110 @@ > > > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > > > +/* > > > + * Copyright (C) 2020 Arm Ltd. > > > + */ > > > + > > > +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ > > > +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ > > > + > > > +#define CLK_PLL_PERIPH0 4 > > > + > > > +#define CLK_CPUX 23 > > > + > > > +#define CLK_APB1 28 > > > + > > > +#define CLK_DE 31 > > > +#define CLK_BUS_DE 32 > > > +#define CLK_DEINTERLACE 33 > > > +#define CLK_BUS_DEINTERLACE 34 > > > +#define CLK_G2D 35 > > > +#define CLK_BUS_G2D 36 > > > +#define CLK_GPU0 37 > > > +#define CLK_BUS_GPU 38 > > > +#define CLK_GPU1 39 > > > +#define CLK_CE 40 > > > +#define CLK_BUS_CE 41 > > > +#define CLK_VE 42 > > > +#define CLK_BUS_VE 43 > > > +#define CLK_BUS_DMA 44 > > > +#define CLK_BUS_HSTIMER 45 > > > +#define CLK_AVS 46 > > > +#define CLK_BUS_DBG 47 > > > +#define CLK_BUS_PSI 48 > > > +#define CLK_BUS_PWM 49 > > > +#define CLK_BUS_IOMMU 50 > > > + > > > +#define CLK_MBUS_DMA 52 > > > +#define CLK_MBUS_VE 53 > > > +#define CLK_MBUS_CE 54 > > > +#define CLK_MBUS_TS 55 > > > +#define CLK_MBUS_NAND 56 > > > +#define CLK_MBUS_G2D 57 > > > + > > > +#define CLK_NAND0 59 > > > +#define CLK_NAND1 60 > > > +#define CLK_BUS_NAND 61 > > > +#define CLK_MMC0 62 > > > +#define CLK_MMC1 63 > > > +#define CLK_MMC2 64 > > > +#define CLK_BUS_MMC0 65 > > > +#define CLK_BUS_MMC1 66 > > > +#define CLK_BUS_MMC2 67 > > > +#define CLK_BUS_UART0 68 > > > +#define CLK_BUS_UART1 69 > > > +#define CLK_BUS_UART2 70 > > > +#define CLK_BUS_UART3 71 > > > +#define CLK_BUS_UART4 72 > > > +#define CLK_BUS_UART5 73 > > > +#define CLK_BUS_I2C0 74 > > > +#define CLK_BUS_I2C1 75 > > > +#define CLK_BUS_I2C2 76 > > > +#define CLK_BUS_I2C3 77 > > > +#define CLK_BUS_I2C4 78 > > > +#define CLK_SPI0 79 > > > +#define CLK_SPI1 80 > > > +#define CLK_BUS_SPI0 81 > > > +#define CLK_BUS_SPI1 82 > > > +#define CLK_EMAC_25M 83 > > > +#define CLK_BUS_EMAC0 84 > > > +#define CLK_BUS_EMAC1 85 > > > +#define CLK_TS 86 > > > +#define CLK_BUS_TS 87 > > > +#define CLK_BUS_THS 88 > > > +#define CLK_SPDIF 89 > > > +#define CLK_BUS_SPDIF 90 > > > +#define CLK_DMIC 91 > > > +#define CLK_BUS_DMIC 92 > > > +#define CLK_AUDIO_CODEC_1X 93 > > > +#define CLK_AUDIO_CODEC_4X 94 > > > +#define CLK_BUS_AUDIO_CODEC 95 > > > +#define CLK_AUDIO_HUB 96 > > > +#define CLK_BUS_AUDIO_HUB 97 > > > +#define CLK_USB_OHCI0 98 > > > +#define CLK_USB_PHY0 99 > > > +#define CLK_USB_OHCI1 100 > > > +#define CLK_USB_PHY1 101 > > > +#define CLK_USB_OHCI2 102 > > > +#define CLK_USB_PHY2 103 > > > +#define CLK_USB_OHCI3 104 > > > +#define CLK_USB_PHY3 105 > > > +#define CLK_BUS_OHCI0 106 > > > +#define CLK_BUS_OHCI1 107 > > > +#define CLK_BUS_OHCI2 108 > > > +#define CLK_BUS_OHCI3 109 > > > +#define CLK_BUS_EHCI0 110 > > > +#define CLK_BUS_EHCI1 111 > > > +#define CLK_BUS_EHCI2 112 > > > +#define CLK_BUS_EHCI3 113 > > > +#define CLK_BUS_OTG 114 > > > +#define CLK_BUS_KEYADC 115 > > > +#define CLK_HDMI 116 > > > +#define CLK_HDMI_SLOW 117 > > > +#define CLK_HDMI_CEC 118 > > > +#define CLK_BUS_HDMI 119 > > > +#define CLK_BUS_TCON_TOP 120 > > > +#define CLK_TCON_TV0 121 > > > +#define CLK_BUS_TCON_TV0 122 > > > +#define CLK_HDCP 123 > > > +#define CLK_BUS_HDCP 124 > > > + > > > +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ > > > diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h > > > b/include/dt-bindings/reset/sun50i-h616-ccu.h > > > new file mode 100644 > > > index 000000000000..1c992cfbbbab > > > --- /dev/null > > > +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h > > > @@ -0,0 +1,67 @@ > > > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > > > +/* > > > + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> > > > + */ > > > + > > > +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ > > > +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ > > > + > > > +#define RST_MBUS 0 > > > +#define RST_BUS_DE 1 > > > +#define RST_BUS_DEINTERLACE 2 > > > +#define RST_BUS_GPU 3 > > > +#define RST_BUS_CE 4 > > > +#define RST_BUS_VE 5 > > > +#define RST_BUS_DMA 6 > > > +#define RST_BUS_HSTIMER 7 > > > +#define RST_BUS_DBG 8 > > > +#define RST_BUS_PSI 9 > > > +#define RST_BUS_PWM 10 > > > +#define RST_BUS_IOMMU 11 > > > +#define RST_BUS_DRAM 12 > > > +#define RST_BUS_NAND 13 > > > +#define RST_BUS_MMC0 14 > > > +#define RST_BUS_MMC1 15 > > > +#define RST_BUS_MMC2 16 > > > +#define RST_BUS_UART0 17 > > > +#define RST_BUS_UART1 18 > > > +#define RST_BUS_UART2 19 > > > +#define RST_BUS_UART3 20 > > > +#define RST_BUS_UART4 21 > > > +#define RST_BUS_UART5 22 > > > +#define RST_BUS_I2C0 23 > > > +#define RST_BUS_I2C1 24 > > > +#define RST_BUS_I2C2 25 > > > +#define RST_BUS_I2C3 26 > > > +#define RST_BUS_I2C4 27 > > > +#define RST_BUS_SPI0 28 > > > +#define RST_BUS_SPI1 29 > > > +#define RST_BUS_EMAC0 30 > > > +#define RST_BUS_EMAC1 31 > > > +#define RST_BUS_TS 32 > > > +#define RST_BUS_THS 33 > > > +#define RST_BUS_SPDIF 34 > > > +#define RST_BUS_DMIC 35 > > > +#define RST_BUS_AUDIO_CODEC 36 > > > +#define RST_BUS_AUDIO_HUB 37 > > > +#define RST_USB_PHY0 38 > > > +#define RST_USB_PHY1 39 > > > +#define RST_USB_PHY2 40 > > > +#define RST_USB_PHY3 41 > > > +#define RST_BUS_OHCI0 42 > > > +#define RST_BUS_OHCI1 43 > > > +#define RST_BUS_OHCI2 44 > > > +#define RST_BUS_OHCI3 45 > > > +#define RST_BUS_EHCI0 46 > > > +#define RST_BUS_EHCI1 47 > > > +#define RST_BUS_EHCI2 48 > > > +#define RST_BUS_EHCI3 49 > > > +#define RST_BUS_OTG 50 > > > +#define RST_BUS_HDMI 51 > > > +#define RST_BUS_HDMI_SUB 52 > > > +#define RST_BUS_TCON_TOP 53 > > > +#define RST_BUS_TCON_TV0 54 > > > +#define RST_BUS_HDCP 55 > > > +#define RST_BUS_KEYADC 56 > > > + > > > +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ > > > -- > > > 2.17.5 > > > > > > > > >
Hi Andre, I try to review this, and compare against the vendor Kernel On Wed, 2 Dec 2020 at 14:54, Andre Przywara <andre.przywara@arm.com> wrote: > > While the clocks are fairly similar to the H6, many differ in tiny > details, so a separate clock driver seems indicated. > > Derived from the H6 clock driver, and adjusted according to the manual. > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > --- > drivers/clk/sunxi-ng/Kconfig | 7 +- > drivers/clk/sunxi-ng/Makefile | 1 + > drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ > drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + > include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ > include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ > 6 files changed, 1376 insertions(+), 1 deletion(-) > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h > create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h > create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h > > diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig > index ce5f5847d5d3..cd46d8853876 100644 > --- a/drivers/clk/sunxi-ng/Kconfig > +++ b/drivers/clk/sunxi-ng/Kconfig > @@ -32,8 +32,13 @@ config SUN50I_H6_CCU > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > +config SUN50I_H616_CCU > + bool "Support for the Allwinner H616 CCU" > + default ARM64 && ARCH_SUNXI > + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > + > config SUN50I_H6_R_CCU > - bool "Support for the Allwinner H6 PRCM CCU" > + bool "Support for the Allwinner H6 and H616 PRCM CCU" > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile > index 3eb5cff40eac..96c324306d97 100644 > --- a/drivers/clk/sunxi-ng/Makefile > +++ b/drivers/clk/sunxi-ng/Makefile > @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o > obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o > obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o > obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o > +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o > obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o > obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o > obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > new file mode 100644 > index 000000000000..3fbb258f0354 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > @@ -0,0 +1,1134 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Arm Ltd. > + * Based on the H6 CCU driver, which is: > + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/io.h> > +#include <linux/of_address.h> > +#include <linux/platform_device.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-sun50i-h616.h" > + > +/* > + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However > + * P should only be used for output frequencies lower than 288 MHz. > + * > + * For now we can just model it as a multiplier clock, and force P to /1. > + * > + * The M factor is present in the register's description, but not in the > + * frequency formula, and it's documented as "M is only used for backdoor > + * testing", so it's not modelled and then force to 0. > + */ > +#define SUN50I_H616_PLL_CPUX_REG 0x000 > +static struct ccu_mult pll_cpux_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .common = { > + .reg = 0x000, > + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", > + &ccu_mult_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ > +#define SUN50I_H616_PLL_DDR0_REG 0x010 > +static struct ccu_nkmp pll_ddr0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x010, > + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DDR1_REG 0x018 > +static struct ccu_nkmp pll_ddr1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x018, > + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 > +static struct ccu_nkmp pll_periph0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, > + .common = { > + .reg = 0x020, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 > +static struct ccu_nkmp pll_periph1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, > + .common = { > + .reg = 0x028, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_GPU_REG 0x030 > +static struct ccu_nkmp pll_gpu_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x030, > + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * For Video PLLs, the output divider is described as "used for testing" > + * in the user manual. So it's not modelled and forced to 0. > + */ > +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 > +static struct ccu_nm pll_video0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x040, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; FYI the PLL video0 in your code is similar between H6/H616 but it's not the same in the vendor kernel. Vendor says for H6: pll_video0/pll_video1: 24*N/D1/4 for H616: pll_video0x4 24*N/D1 pll_video1/pll_video2: 24*N/D1/4 I'm not sure if this comment is correct or not. > + > +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 > +static struct ccu_nm pll_video1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x048, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 > +static struct ccu_nm pll_video2_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x050, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; There is also a PLL_CSI. And all the CSI / LCD clocks but they are no output pins available in the H616. Maybe we can introduced these clocks later. > + > +#define SUN50I_H616_PLL_VE_REG 0x058 > +static struct ccu_nkmp pll_ve_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x058, > + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DE_REG 0x060 > +static struct ccu_nkmp pll_de_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x060, > + .hw.init = CLK_HW_INIT("pll-de", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * TODO: Determine SDM settings for the audio PLL. The manual suggests > + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b > + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, > + * pattern=0xe001288c for 22.5792 MHz. > + * This clashes with our fixed PLL_POST_DIV_P. > + */ > +#define SUN50I_H616_PLL_AUDIO_REG 0x078 > +static struct ccu_nm pll_audio_hs_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .common = { > + .reg = 0x078, > + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +static const char * const cpux_parents[] = { "osc24M", "osc32k", > + "iosc", "pll-cpux", "pll-periph0" }; > +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, > + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); > +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); > +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); > + > +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", "osc32k", > + "iosc", "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", > + psi_ahb1_ahb2_parents, > + 0x510, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", > + "psi-ahb1-ahb2", > + "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", > + "pll-ddr0", "pll-ddr1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, > + 0, 3, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_IS_CRITICAL); > + > +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", > + 0x60c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", > + de_parents, > + 0x620, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi-ahb1-ahb2", > + 0x62c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", > + 0x63c, BIT(0), 0); > + > +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, > + 0, 2, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, > + 0, 3, /* M */ M here should be 0,2 > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", > + 0x67c, BIT(0), 0); > + > +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", > + 0x68c, BIT(0), 0); > + > +static const char * const ve_parents[] = { "pll-ve" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, > + 0, 3, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", > + 0x69c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", > + 0x70c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", > + 0x73c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); > + > +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", > + 0x78c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", > + 0x79c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); > + > +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; > +static struct ccu_div dram_clk = { > + .div = _SUNXI_CCU_DIV(0, 2), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0x800, > + .hw.init = CLK_HW_INIT_PARENTS("dram", > + dram_parents, > + &ccu_div_ops, > + CLK_IS_CRITICAL), > + }, > +}; > + > +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", > + 0x804, BIT(0), 0); > +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", > + 0x804, BIT(1), 0); > +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", > + 0x804, BIT(2), 0); > +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", > + 0x804, BIT(3), 0); > +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", > + 0x804, BIT(5), 0); Compare to H6, you drop mbus-deinterlace but it is present in the vendor kernel. > +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", > + 0x804, BIT(10), 0); > + > +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", > + 0x80c, BIT(0), CLK_IS_CRITICAL); > + > +static const char * const nand_spi_parents[] = { "osc24M", "pll-periph0", > + "pll-periph1", "pll-periph0-2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); > + > +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div */ > + 0); > + > +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); > + > +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0); > +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); > + > +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); > + > +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, > + BIT(31) | BIT(30), 0); > + > +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, BIT(1), 0); > + > +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); > + > +static const char * const audio_parents[] = { "pll-audio-1x", "pll-audio-2x", > + "pll-audio-4x", "pll-audio-hs" }; > +static struct ccu_div spdif_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa20, > + .hw.init = CLK_HW_INIT_PARENTS("spdif", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); > + > +static struct ccu_div dmic_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa40, > + .hw.init = CLK_HW_INIT_PARENTS("dmic", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", > + audio_parents, 0xa50, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", > + audio_parents, 0xa54, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c, > + BIT(0), 0); > + > +static struct ccu_div audio_hub_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa60, > + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, BIT(0), 0); > + > +/* > + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. > + * We will force them to 0 (12M divided from 48M). > + */ > +#define SUN50I_H616_USB0_CLK_REG 0xa70 > +#define SUN50I_H616_USB1_CLK_REG 0xa74 > +#define SUN50I_H616_USB2_CLK_REG 0xa78 > +#define SUN50I_H616_USB3_CLK_REG 0xa7c > + > +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, BIT(29), 0); > + > +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); > +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0); > +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, BIT(2), 0); > +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, BIT(3), 0); > +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); > +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); > +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, BIT(6), 0); > +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0); > +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); > + > +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, BIT(0), 0); > + > +static struct clk_fixed_factor pll_periph0_4x_clk; > + > +static const char * const hdmi_parents[] = { "pll-video0", "pll-video0-4x", > + "pll-video2", "pll-video2-4x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, BIT(31), 0); > + > +static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; > +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { > + { .index = 1, .div = 36621 }, > +}; > + > +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 > +static struct ccu_mux hdmi_cec_clk = { > + .enable = BIT(31), > + > + .mux = { > + .shift = 24, > + .width = 2, > + > + .fixed_predivs = hdmi_cec_predivs, > + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), > + }, > + > + .common = { > + .reg = 0xb10, > + .features = CCU_FEATURE_VARIABLE_PREDIV, > + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", > + hdmi_cec_parents, > + &ccu_mux_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", > + 0xb5c, BIT(0), 0); > + > +static const char * const tcon_tv0_parents[] = { "pll-video0", > + "pll-video0-4x", > + "pll-video1", > + "pll-video1-4x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", > + tcon_tv0_parents, 0xb80, > + 0, 4, /* M */ > + 8, 2, /* P */ > + 24, 3, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", > + 0xb9c, BIT(0), 0); The TV1 clk is missing here > + > +static const char * const hdcp_parents[] = { "pll-periph0", "pll-periph1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0); > + > +/* Fixed factor clocks */ > +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); > + > +static const struct clk_hw *clk_parent_pll_audio[] = { > + &pll_audio_hs_clk.common.hw > +}; > + > +/* > + * The divider of pll-audio is fixed to 24 for now, so 24576000 and 22579200 > + * rates can be set exactly in conjunction with sigma-delta modulation. > + */ > +static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", > + clk_parent_pll_audio, > + 96, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", > + clk_parent_pll_audio, > + 48, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", > + clk_parent_pll_audio, > + 24, 1, CLK_SET_RATE_PARENT); > + > +static const struct clk_hw *pll_periph0_parents[] = { > + &pll_periph0_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x", > + pll_periph0_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x", > + pll_periph0_parents, > + 1, 2, 0); > + > +static const struct clk_hw *pll_periph1_parents[] = { > + &pll_periph1_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x", > + pll_periph1_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x", > + pll_periph1_parents, > + 1, 2, 0); > + > +static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x", > + &pll_video0_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x", > + &pll_video1_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video2_4x_clk, "pll-video2-4x", > + &pll_video2_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > + > +static struct ccu_common *sun50i_h616_ccu_clks[] = { > + &pll_cpux_clk.common, > + &pll_ddr0_clk.common, > + &pll_ddr1_clk.common, > + &pll_periph0_clk.common, > + &pll_periph1_clk.common, > + &pll_gpu_clk.common, > + &pll_video0_clk.common, > + &pll_video1_clk.common, > + &pll_video2_clk.common, > + &pll_ve_clk.common, > + &pll_de_clk.common, > + &pll_audio_hs_clk.common, > + &cpux_clk.common, > + &axi_clk.common, > + &cpux_apb_clk.common, > + &psi_ahb1_ahb2_clk.common, > + &ahb3_clk.common, > + &apb1_clk.common, > + &apb2_clk.common, > + &mbus_clk.common, > + &de_clk.common, > + &bus_de_clk.common, > + &deinterlace_clk.common, > + &bus_deinterlace_clk.common, > + &g2d_clk.common, > + &bus_g2d_clk.common, > + &gpu0_clk.common, > + &bus_gpu_clk.common, > + &gpu1_clk.common, > + &ce_clk.common, > + &bus_ce_clk.common, > + &ve_clk.common, > + &bus_ve_clk.common, > + &bus_dma_clk.common, > + &bus_hstimer_clk.common, > + &avs_clk.common, > + &bus_dbg_clk.common, > + &bus_psi_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_ts_clk.common, > + &mbus_nand_clk.common, > + &mbus_g2d_clk.common, > + &bus_dram_clk.common, > + &nand0_clk.common, > + &nand1_clk.common, > + &bus_nand_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_uart4_clk.common, > + &bus_uart5_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, > + &bus_spi0_clk.common, > + &bus_spi1_clk.common, > + &emac_25m_clk.common, > + &bus_emac0_clk.common, > + &bus_emac1_clk.common, > + &ts_clk.common, > + &bus_ts_clk.common, > + &bus_ths_clk.common, > + &spdif_clk.common, > + &bus_spdif_clk.common, > + &dmic_clk.common, > + &bus_dmic_clk.common, > + &audio_codec_1x_clk.common, > + &audio_codec_4x_clk.common, > + &bus_audio_codec_clk.common, > + &audio_hub_clk.common, > + &bus_audio_hub_clk.common, > + &usb_ohci0_clk.common, > + &usb_phy0_clk.common, > + &usb_ohci1_clk.common, > + &usb_phy1_clk.common, > + &usb_ohci2_clk.common, > + &usb_phy2_clk.common, > + &usb_ohci3_clk.common, > + &usb_phy3_clk.common, > + &bus_ohci0_clk.common, > + &bus_ohci1_clk.common, > + &bus_ohci2_clk.common, > + &bus_ohci3_clk.common, > + &bus_ehci0_clk.common, > + &bus_ehci1_clk.common, > + &bus_ehci2_clk.common, > + &bus_ehci3_clk.common, > + &bus_otg_clk.common, > + &bus_keyadc_clk.common, > + &hdmi_clk.common, > + &hdmi_slow_clk.common, > + &hdmi_cec_clk.common, > + &bus_hdmi_clk.common, > + &bus_tcon_top_clk.common, > + &tcon_tv0_clk.common, > + &bus_tcon_tv0_clk.common, > + &hdcp_clk.common, > + &bus_hdcp_clk.common, > +}; > + > +static struct clk_hw_onecell_data sun50i_h616_hw_clks = { > + .hws = { > + [CLK_OSC12M] = &osc12M_clk.hw, > + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, > + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, > + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, > + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, > + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, > + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, > + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, > + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, > + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, > + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, > + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, > + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, > + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, > + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, > + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, > + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, > + [CLK_PLL_VE] = &pll_ve_clk.common.hw, > + [CLK_PLL_DE] = &pll_de_clk.common.hw, > + [CLK_PLL_AUDIO_HS] = &pll_audio_hs_clk.common.hw, > + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.hw, > + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, > + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, > + [CLK_CPUX] = &cpux_clk.common.hw, > + [CLK_AXI] = &axi_clk.common.hw, > + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, > + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw, > + [CLK_AHB3] = &ahb3_clk.common.hw, > + [CLK_APB1] = &apb1_clk.common.hw, > + [CLK_APB2] = &apb2_clk.common.hw, > + [CLK_MBUS] = &mbus_clk.common.hw, > + [CLK_DE] = &de_clk.common.hw, > + [CLK_BUS_DE] = &bus_de_clk.common.hw, > + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, > + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, > + [CLK_G2D] = &g2d_clk.common.hw, > + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, > + [CLK_GPU0] = &gpu0_clk.common.hw, > + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, > + [CLK_GPU1] = &gpu1_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_BUS_DMA] = &bus_dma_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_PSI] = &bus_psi_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_TS] = &mbus_ts_clk.common.hw, > + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, > + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, > + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, > + [CLK_NAND0] = &nand0_clk.common.hw, > + [CLK_NAND1] = &nand1_clk.common.hw, > + [CLK_BUS_NAND] = &bus_nand_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_UART4] = &bus_uart4_clk.common.hw, > + [CLK_BUS_UART5] = &bus_uart5_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_BUS_SPI0] = &bus_spi0_clk.common.hw, > + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, > + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, > + [CLK_BUS_EMAC0] = &bus_emac0_clk.common.hw, > + [CLK_BUS_EMAC1] = &bus_emac1_clk.common.hw, > + [CLK_TS] = &ts_clk.common.hw, > + [CLK_BUS_TS] = &bus_ts_clk.common.hw, > + [CLK_BUS_THS] = &bus_ths_clk.common.hw, > + [CLK_SPDIF] = &spdif_clk.common.hw, > + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, > + [CLK_DMIC] = &dmic_clk.common.hw, > + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, > + [CLK_AUDIO_CODEC_1X] = &audio_codec_1x_clk.common.hw, > + [CLK_AUDIO_CODEC_4X] = &audio_codec_4x_clk.common.hw, > + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw, > + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, > + [CLK_BUS_AUDIO_HUB] = &bus_audio_hub_clk.common.hw, > + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, > + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, > + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, > + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, > + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, > + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, > + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, > + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, > + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, > + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, > + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, > + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, > + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, > + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, > + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, > + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, > + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, > + [CLK_BUS_KEYADC] = &bus_keyadc_clk.common.hw, > + [CLK_HDMI] = &hdmi_clk.common.hw, > + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, > + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, > + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, > + [CLK_BUS_TCON_TOP] = &bus_tcon_top_clk.common.hw, > + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, > + [CLK_BUS_TCON_TV0] = &bus_tcon_tv0_clk.common.hw, > + [CLK_HDCP] = &hdcp_clk.common.hw, > + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, > + }, > + .num = CLK_NUMBER, > +}; > + > +static struct ccu_reset_map sun50i_h616_ccu_resets[] = { > + [RST_MBUS] = { 0x540, BIT(30) }, > + > + [RST_BUS_DE] = { 0x60c, BIT(16) }, > + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, > + [RST_BUS_GPU] = { 0x67c, BIT(16) }, > + [RST_BUS_CE] = { 0x68c, BIT(16) }, > + [RST_BUS_VE] = { 0x69c, BIT(16) }, > + [RST_BUS_DMA] = { 0x70c, BIT(16) }, > + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, > + [RST_BUS_DBG] = { 0x78c, BIT(16) }, > + [RST_BUS_PSI] = { 0x79c, BIT(16) }, > + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, > + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, > + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, > + [RST_BUS_NAND] = { 0x82c, 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_UART4] = { 0x90c, BIT(20) }, > + [RST_BUS_UART5] = { 0x90c, BIT(21) }, > + [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_EMAC0] = { 0x97c, BIT(16) }, > + [RST_BUS_EMAC1] = { 0x97c, BIT(17) }, > + [RST_BUS_TS] = { 0x9bc, BIT(16) }, > + [RST_BUS_THS] = { 0x9fc, BIT(16) }, > + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, > + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, > + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, > + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, > + > + [RST_USB_PHY0] = { 0xa70, BIT(30) }, > + [RST_USB_PHY1] = { 0xa74, BIT(30) }, > + [RST_USB_PHY2] = { 0xa78, BIT(30) }, > + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, > + > + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, > + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, > + [RST_BUS_OHCI2] = { 0xa8c, BIT(18) }, > + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, > + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, > + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, > + [RST_BUS_EHCI2] = { 0xa8c, BIT(22) }, > + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, > + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, > + [RST_BUS_KEYADC] = { 0xa9c, BIT(16) }, > + > + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, > + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, > + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, > + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, > + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, > +}; > + > +static const struct sunxi_ccu_desc sun50i_h616_ccu_desc = { > + .ccu_clks = sun50i_h616_ccu_clks, > + .num_ccu_clks = ARRAY_SIZE(sun50i_h616_ccu_clks), > + > + .hw_clks = &sun50i_h616_hw_clks, > + > + .resets = sun50i_h616_ccu_resets, > + .num_resets = ARRAY_SIZE(sun50i_h616_ccu_resets), > +}; > + > +static const u32 pll_regs[] = { > + SUN50I_H616_PLL_CPUX_REG, > + SUN50I_H616_PLL_DDR0_REG, > + SUN50I_H616_PLL_DDR1_REG, > + SUN50I_H616_PLL_PERIPH0_REG, > + SUN50I_H616_PLL_PERIPH1_REG, > + SUN50I_H616_PLL_GPU_REG, > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > + SUN50I_H616_PLL_VE_REG, > + SUN50I_H616_PLL_DE_REG, > + SUN50I_H616_PLL_AUDIO_REG, > +}; > + > +static const u32 pll_video_regs[] = { > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > +}; > + > +static const u32 usb2_clk_regs[] = { > + SUN50I_H616_USB0_CLK_REG, > + SUN50I_H616_USB1_CLK_REG, > + SUN50I_H616_USB2_CLK_REG, > + SUN50I_H616_USB3_CLK_REG, > +}; > + > +static int sun50i_h616_ccu_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + void __iomem *reg; > + u32 val; > + int i; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + reg = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(reg)) > + return PTR_ERR(reg); > + > + /* Enable the lock bits on all PLLs */ > + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { > + val = readl(reg + pll_regs[i]); > + val |= BIT(29); > + writel(val, reg + pll_regs[i]); > + } > + > + /* > + * Force the output divider of video PLLs to 0. > + * > + * See the comment before pll-video0 definition for the reason. > + */ > + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { > + val = readl(reg + pll_video_regs[i]); > + val &= ~BIT(0); > + writel(val, reg + pll_video_regs[i]); > + } > + > + /* > + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) > + * > + * This clock mux is still mysterious, and the code just enforces > + * it to have a valid clock parent. > + */ > + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { > + val = readl(reg + usb2_clk_regs[i]); > + val &= ~GENMASK(25, 24); > + writel (val, reg + usb2_clk_regs[i]); > + } > + > + /* > + * Force the post-divider of pll-audio to 12 and the output divider > + * of it to 2, so 24576000 and 22579200 rates can be set exactly. > + */ > + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); > + val &= ~(GENMASK(21, 16) | BIT(0)); > + writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG); > + > + /* > + * First clock parent (osc32K) is unusable for CEC. But since there > + * is no good way to force parent switch (both run with same frequency), > + * just set second clock parent here. > + */ > + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + val |= BIT(24); > + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + > + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h616_ccu_desc); > +} > + > +static const struct of_device_id sun50i_h616_ccu_ids[] = { > + { .compatible = "allwinner,sun50i-h616-ccu", > + .data = &sun50i_h616_ccu_desc }, > + { } > +}; > + > +static struct platform_driver sun50i_h616_ccu_driver = { > + .probe = sun50i_h616_ccu_probe, > + .driver = { > + .name = "sun50i-h616-ccu", > + .of_match_table = sun50i_h616_ccu_ids, > + }, > +}; > +builtin_platform_driver(sun50i_h616_ccu_driver); > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > new file mode 100644 > index 000000000000..da8f0b1206f9 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > @@ -0,0 +1,58 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright 2020 Arm Ltd. > + */ > + > +#ifndef _CCU_SUN50I_H616_H_ > +#define _CCU_SUN50I_H616_H_ > + > +#include <dt-bindings/clock/sun50i-h616-ccu.h> > +#include <dt-bindings/reset/sun50i-h616-ccu.h> > + > +#define CLK_OSC12M 0 > +#define CLK_PLL_CPUX 1 > +#define CLK_PLL_DDR0 2 > +#define CLK_PLL_DDR1 3 > + > +/* PLL_PERIPH0 exported for PRCM */ > + > +#define CLK_PLL_PERIPH0_2X 5 > +#define CLK_PLL_PERIPH0_4X 6 > +#define CLK_PLL_PERIPH1 7 > +#define CLK_PLL_PERIPH1_2X 8 > +#define CLK_PLL_PERIPH1_4X 9 > +#define CLK_PLL_GPU 10 > +#define CLK_PLL_VIDEO0 11 > +#define CLK_PLL_VIDEO0_4X 12 > +#define CLK_PLL_VIDEO1 13 > +#define CLK_PLL_VIDEO1_4X 14 > +#define CLK_PLL_VIDEO2 15 > +#define CLK_PLL_VIDEO2_4X 16 > +#define CLK_PLL_VE 17 > +#define CLK_PLL_DE 18 > +#define CLK_PLL_AUDIO_HS 19 > +#define CLK_PLL_AUDIO_1X 20 > +#define CLK_PLL_AUDIO_2X 21 > +#define CLK_PLL_AUDIO_4X 22 > + > +/* CPUX clock exported for DVFS */ > + > +#define CLK_AXI 24 > +#define CLK_CPUX_APB 25 > +#define CLK_PSI_AHB1_AHB2 26 > +#define CLK_AHB3 27 > + > +/* APB1 clock exported for PIO */ > + > +#define CLK_APB2 29 > +#define CLK_MBUS 30 > + > +/* All module clocks and bus gates are exported except DRAM */ > + > +#define CLK_DRAM 51 > + > +#define CLK_BUS_DRAM 58 > + > +#define CLK_NUMBER (CLK_BUS_HDCP + 1) > + > +#endif /* _CCU_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h b/include/dt-bindings/clock/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..a9cc8844e3a9 > --- /dev/null > +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h > @@ -0,0 +1,110 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2020 Arm Ltd. > + */ > + > +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ > +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ > + > +#define CLK_PLL_PERIPH0 4 > + > +#define CLK_CPUX 23 > + > +#define CLK_APB1 28 > + > +#define CLK_DE 31 > +#define CLK_BUS_DE 32 > +#define CLK_DEINTERLACE 33 > +#define CLK_BUS_DEINTERLACE 34 > +#define CLK_G2D 35 > +#define CLK_BUS_G2D 36 > +#define CLK_GPU0 37 > +#define CLK_BUS_GPU 38 > +#define CLK_GPU1 39 > +#define CLK_CE 40 > +#define CLK_BUS_CE 41 > +#define CLK_VE 42 > +#define CLK_BUS_VE 43 > +#define CLK_BUS_DMA 44 > +#define CLK_BUS_HSTIMER 45 > +#define CLK_AVS 46 > +#define CLK_BUS_DBG 47 > +#define CLK_BUS_PSI 48 > +#define CLK_BUS_PWM 49 > +#define CLK_BUS_IOMMU 50 > + > +#define CLK_MBUS_DMA 52 > +#define CLK_MBUS_VE 53 > +#define CLK_MBUS_CE 54 > +#define CLK_MBUS_TS 55 > +#define CLK_MBUS_NAND 56 > +#define CLK_MBUS_G2D 57 > + > +#define CLK_NAND0 59 > +#define CLK_NAND1 60 > +#define CLK_BUS_NAND 61 > +#define CLK_MMC0 62 > +#define CLK_MMC1 63 > +#define CLK_MMC2 64 > +#define CLK_BUS_MMC0 65 > +#define CLK_BUS_MMC1 66 > +#define CLK_BUS_MMC2 67 > +#define CLK_BUS_UART0 68 > +#define CLK_BUS_UART1 69 > +#define CLK_BUS_UART2 70 > +#define CLK_BUS_UART3 71 > +#define CLK_BUS_UART4 72 > +#define CLK_BUS_UART5 73 > +#define CLK_BUS_I2C0 74 > +#define CLK_BUS_I2C1 75 > +#define CLK_BUS_I2C2 76 > +#define CLK_BUS_I2C3 77 > +#define CLK_BUS_I2C4 78 > +#define CLK_SPI0 79 > +#define CLK_SPI1 80 > +#define CLK_BUS_SPI0 81 > +#define CLK_BUS_SPI1 82 > +#define CLK_EMAC_25M 83 > +#define CLK_BUS_EMAC0 84 > +#define CLK_BUS_EMAC1 85 > +#define CLK_TS 86 > +#define CLK_BUS_TS 87 > +#define CLK_BUS_THS 88 > +#define CLK_SPDIF 89 > +#define CLK_BUS_SPDIF 90 > +#define CLK_DMIC 91 > +#define CLK_BUS_DMIC 92 > +#define CLK_AUDIO_CODEC_1X 93 > +#define CLK_AUDIO_CODEC_4X 94 > +#define CLK_BUS_AUDIO_CODEC 95 > +#define CLK_AUDIO_HUB 96 > +#define CLK_BUS_AUDIO_HUB 97 > +#define CLK_USB_OHCI0 98 > +#define CLK_USB_PHY0 99 > +#define CLK_USB_OHCI1 100 > +#define CLK_USB_PHY1 101 > +#define CLK_USB_OHCI2 102 > +#define CLK_USB_PHY2 103 > +#define CLK_USB_OHCI3 104 > +#define CLK_USB_PHY3 105 > +#define CLK_BUS_OHCI0 106 > +#define CLK_BUS_OHCI1 107 > +#define CLK_BUS_OHCI2 108 > +#define CLK_BUS_OHCI3 109 > +#define CLK_BUS_EHCI0 110 > +#define CLK_BUS_EHCI1 111 > +#define CLK_BUS_EHCI2 112 > +#define CLK_BUS_EHCI3 113 > +#define CLK_BUS_OTG 114 > +#define CLK_BUS_KEYADC 115 > +#define CLK_HDMI 116 > +#define CLK_HDMI_SLOW 117 > +#define CLK_HDMI_CEC 118 > +#define CLK_BUS_HDMI 119 > +#define CLK_BUS_TCON_TOP 120 > +#define CLK_TCON_TV0 121 > +#define CLK_BUS_TCON_TV0 122 > +#define CLK_HDCP 123 > +#define CLK_BUS_HDCP 124 > + > +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h b/include/dt-bindings/reset/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..1c992cfbbbab > --- /dev/null > +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h > @@ -0,0 +1,67 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ > +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ > + > +#define RST_MBUS 0 > +#define RST_BUS_DE 1 > +#define RST_BUS_DEINTERLACE 2 > +#define RST_BUS_GPU 3 > +#define RST_BUS_CE 4 > +#define RST_BUS_VE 5 > +#define RST_BUS_DMA 6 > +#define RST_BUS_HSTIMER 7 > +#define RST_BUS_DBG 8 > +#define RST_BUS_PSI 9 > +#define RST_BUS_PWM 10 > +#define RST_BUS_IOMMU 11 > +#define RST_BUS_DRAM 12 > +#define RST_BUS_NAND 13 > +#define RST_BUS_MMC0 14 > +#define RST_BUS_MMC1 15 > +#define RST_BUS_MMC2 16 > +#define RST_BUS_UART0 17 > +#define RST_BUS_UART1 18 > +#define RST_BUS_UART2 19 > +#define RST_BUS_UART3 20 > +#define RST_BUS_UART4 21 > +#define RST_BUS_UART5 22 > +#define RST_BUS_I2C0 23 > +#define RST_BUS_I2C1 24 > +#define RST_BUS_I2C2 25 > +#define RST_BUS_I2C3 26 > +#define RST_BUS_I2C4 27 > +#define RST_BUS_SPI0 28 > +#define RST_BUS_SPI1 29 > +#define RST_BUS_EMAC0 30 > +#define RST_BUS_EMAC1 31 > +#define RST_BUS_TS 32 > +#define RST_BUS_THS 33 > +#define RST_BUS_SPDIF 34 > +#define RST_BUS_DMIC 35 > +#define RST_BUS_AUDIO_CODEC 36 > +#define RST_BUS_AUDIO_HUB 37 > +#define RST_USB_PHY0 38 > +#define RST_USB_PHY1 39 > +#define RST_USB_PHY2 40 > +#define RST_USB_PHY3 41 > +#define RST_BUS_OHCI0 42 > +#define RST_BUS_OHCI1 43 > +#define RST_BUS_OHCI2 44 > +#define RST_BUS_OHCI3 45 > +#define RST_BUS_EHCI0 46 > +#define RST_BUS_EHCI1 47 > +#define RST_BUS_EHCI2 48 > +#define RST_BUS_EHCI3 49 > +#define RST_BUS_OTG 50 > +#define RST_BUS_HDMI 51 > +#define RST_BUS_HDMI_SUB 52 > +#define RST_BUS_TCON_TOP 53 > +#define RST_BUS_TCON_TV0 54 > +#define RST_BUS_HDCP 55 > +#define RST_BUS_KEYADC 56 > + > +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ > -- > 2.17.5 > > -- > You received this message because you are subscribed to the Google Groups "linux-sunxi" group. > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com. > To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/20201202135409.13683-6-andre.przywara%40arm.com.
On 09/12/2020 14:33, Clément Péron wrote: Hi, > I try to review this, and compare against the vendor Kernel> > On Wed, 2 Dec 2020 at 14:54, Andre Przywara <andre.przywara@arm.com> wrote: >> >> While the clocks are fairly similar to the H6, many differ in tiny >> details, so a separate clock driver seems indicated. >> >> Derived from the H6 clock driver, and adjusted according to the manual. >> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com> >> --- >> drivers/clk/sunxi-ng/Kconfig | 7 +- >> drivers/clk/sunxi-ng/Makefile | 1 + >> drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ >> drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + >> include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ >> include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ >> 6 files changed, 1376 insertions(+), 1 deletion(-) >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h >> create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h >> >> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig >> index ce5f5847d5d3..cd46d8853876 100644 >> --- a/drivers/clk/sunxi-ng/Kconfig >> +++ b/drivers/clk/sunxi-ng/Kconfig >> @@ -32,8 +32,13 @@ config SUN50I_H6_CCU >> default ARM64 && ARCH_SUNXI >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> >> +config SUN50I_H616_CCU >> + bool "Support for the Allwinner H616 CCU" >> + default ARM64 && ARCH_SUNXI >> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> + >> config SUN50I_H6_R_CCU >> - bool "Support for the Allwinner H6 PRCM CCU" >> + bool "Support for the Allwinner H6 and H616 PRCM CCU" >> default ARM64 && ARCH_SUNXI >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> >> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile >> index 3eb5cff40eac..96c324306d97 100644 >> --- a/drivers/clk/sunxi-ng/Makefile >> +++ b/drivers/clk/sunxi-ng/Makefile >> @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o >> obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o >> obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o >> obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o >> +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o >> obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o >> obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o >> obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o >> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> new file mode 100644 >> index 000000000000..3fbb258f0354 >> --- /dev/null >> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> @@ -0,0 +1,1134 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Copyright (c) 2020 Arm Ltd. >> + * Based on the H6 CCU driver, which is: >> + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> >> + */ >> + >> +#include <linux/clk-provider.h> >> +#include <linux/io.h> >> +#include <linux/of_address.h> >> +#include <linux/platform_device.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-sun50i-h616.h" >> + >> +/* >> + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However >> + * P should only be used for output frequencies lower than 288 MHz. >> + * >> + * For now we can just model it as a multiplier clock, and force P to /1. >> + * >> + * The M factor is present in the register's description, but not in the >> + * frequency formula, and it's documented as "M is only used for backdoor >> + * testing", so it's not modelled and then force to 0. >> + */ >> +#define SUN50I_H616_PLL_CPUX_REG 0x000 >> +static struct ccu_mult pll_cpux_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .common = { >> + .reg = 0x000, >> + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", >> + &ccu_mult_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ >> +#define SUN50I_H616_PLL_DDR0_REG 0x010 >> +static struct ccu_nkmp pll_ddr0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x010, >> + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_DDR1_REG 0x018 >> +static struct ccu_nkmp pll_ddr1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x018, >> + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 >> +static struct ccu_nkmp pll_periph0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .fixed_post_div = 4, >> + .common = { >> + .reg = 0x020, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 >> +static struct ccu_nkmp pll_periph1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .fixed_post_div = 4, >> + .common = { >> + .reg = 0x028, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_GPU_REG 0x030 >> +static struct ccu_nkmp pll_gpu_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x030, >> + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* >> + * For Video PLLs, the output divider is described as "used for testing" >> + * in the user manual. So it's not modelled and forced to 0. >> + */ >> +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 >> +static struct ccu_nm pll_video0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x040, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; > > FYI the PLL video0 in your code is similar between H6/H616 but it's not the > same in the vendor kernel. > Vendor says for H6: > pll_video0/pll_video1: 24*N/D1/4 > for H616: > pll_video0x4 24*N/D1 > pll_video1/pll_video2: 24*N/D1/4 I don't see any particular problem with this? I mean we pretty surely have the x4 clock on the H6, and for the H616 the manual agrees to your findings? > I'm not sure if this comment is correct or not. > >> + >> +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 >> +static struct ccu_nm pll_video1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x048, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 >> +static struct ccu_nm pll_video2_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x050, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; > > There is also a PLL_CSI. And all the CSI / LCD clocks but they are no > output pins available in the H616. > Maybe we can introduced these clocks later. I don't see good reasons to introduce undocumented and useless clocks at this point. So I will leave this out unless someone protests. >> + >> +#define SUN50I_H616_PLL_VE_REG 0x058 >> +static struct ccu_nkmp pll_ve_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x058, >> + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_DE_REG 0x060 >> +static struct ccu_nkmp pll_de_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x060, >> + .hw.init = CLK_HW_INIT("pll-de", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* >> + * TODO: Determine SDM settings for the audio PLL. The manual suggests >> + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b >> + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, >> + * pattern=0xe001288c for 22.5792 MHz. >> + * This clashes with our fixed PLL_POST_DIV_P. >> + */ >> +#define SUN50I_H616_PLL_AUDIO_REG 0x078 >> +static struct ccu_nm pll_audio_hs_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .common = { >> + .reg = 0x078, >> + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +static const char * const cpux_parents[] = { "osc24M", "osc32k", >> + "iosc", "pll-cpux", "pll-periph0" }; >> +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, >> + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); >> +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); >> +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); >> + >> +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", "osc32k", >> + "iosc", "pll-periph0" }; >> +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", >> + psi_ahb1_ahb2_parents, >> + 0x510, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", >> + "psi-ahb1-ahb2", >> + "pll-periph0" }; >> +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", >> + "pll-ddr0", "pll-ddr1" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, >> + 0, 3, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_IS_CRITICAL); >> + >> +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", >> + 0x60c, BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", >> + de_parents, >> + 0x620, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi-ahb1-ahb2", >> + 0x62c, BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", >> + 0x63c, BIT(0), 0); >> + >> +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, >> + 0, 2, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, >> + 0, 3, /* M */ > > M here should be 0,2 Right, good catch. >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", >> + 0x67c, BIT(0), 0); >> + >> +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 1, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", >> + 0x68c, BIT(0), 0); >> + >> +static const char * const ve_parents[] = { "pll-ve" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, >> + 0, 3, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", >> + 0x69c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", >> + 0x70c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", >> + 0x73c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); >> + >> +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", >> + 0x78c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", >> + 0x79c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); >> + >> +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; >> +static struct ccu_div dram_clk = { >> + .div = _SUNXI_CCU_DIV(0, 2), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0x800, >> + .hw.init = CLK_HW_INIT_PARENTS("dram", >> + dram_parents, >> + &ccu_div_ops, >> + CLK_IS_CRITICAL), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", >> + 0x804, BIT(0), 0); >> +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", >> + 0x804, BIT(1), 0); >> +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", >> + 0x804, BIT(2), 0); >> +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", >> + 0x804, BIT(3), 0); >> +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", >> + 0x804, BIT(5), 0); > > Compare to H6, you drop mbus-deinterlace but it is present in the vendor kernel. It's not in the manual (which is what I look at). Not sure I can trust the vendor kernel more here. >> +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", >> + 0x804, BIT(10), 0); >> + >> +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", >> + 0x80c, BIT(0), CLK_IS_CRITICAL); >> + >> +static const char * const nand_spi_parents[] = { "osc24M", "pll-periph0", >> + "pll-periph1", "pll-periph0-2x", >> + "pll-periph1-2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); >> + >> +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", >> + "pll-periph1-2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); >> + >> +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0); >> +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); >> + >> +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); >> + >> +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, >> + BIT(31) | BIT(30), 0); >> + >> +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, BIT(1), 0); >> + >> +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 1, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); >> + >> +static const char * const audio_parents[] = { "pll-audio-1x", "pll-audio-2x", >> + "pll-audio-4x", "pll-audio-hs" }; >> +static struct ccu_div spdif_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa20, >> + .hw.init = CLK_HW_INIT_PARENTS("spdif", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); >> + >> +static struct ccu_div dmic_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa40, >> + .hw.init = CLK_HW_INIT_PARENTS("dmic", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", >> + audio_parents, 0xa50, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", >> + audio_parents, 0xa54, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c, >> + BIT(0), 0); >> + >> +static struct ccu_div audio_hub_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa60, >> + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, BIT(0), 0); >> + >> +/* >> + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. >> + * We will force them to 0 (12M divided from 48M). >> + */ >> +#define SUN50I_H616_USB0_CLK_REG 0xa70 >> +#define SUN50I_H616_USB1_CLK_REG 0xa74 >> +#define SUN50I_H616_USB2_CLK_REG 0xa78 >> +#define SUN50I_H616_USB3_CLK_REG 0xa7c >> + >> +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); >> +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); >> +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, BIT(6), 0); >> +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0); >> +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); >> + >> +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, BIT(0), 0); >> + >> +static struct clk_fixed_factor pll_periph0_4x_clk; >> + >> +static const char * const hdmi_parents[] = { "pll-video0", "pll-video0-4x", >> + "pll-video2", "pll-video2-4x" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, BIT(31), 0); >> + >> +static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; >> +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { >> + { .index = 1, .div = 36621 }, >> +}; >> + >> +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 >> +static struct ccu_mux hdmi_cec_clk = { >> + .enable = BIT(31), >> + >> + .mux = { >> + .shift = 24, >> + .width = 2, >> + >> + .fixed_predivs = hdmi_cec_predivs, >> + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), >> + }, >> + >> + .common = { >> + .reg = 0xb10, >> + .features = CCU_FEATURE_VARIABLE_PREDIV, >> + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", >> + hdmi_cec_parents, >> + &ccu_mux_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", >> + 0xb5c, BIT(0), 0); >> + >> +static const char * const tcon_tv0_parents[] = { "pll-video0", >> + "pll-video0-4x", >> + "pll-video1", >> + "pll-video1-4x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", >> + tcon_tv0_parents, 0xb80, >> + 0, 4, /* M */ >> + 8, 2, /* P */ >> + 24, 3, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", >> + 0xb9c, BIT(0), 0); > > The TV1 clk is missing here Right, and some more TV encoder related. Cheers, Andre
Dne sreda, 09. december 2020 ob 22:35:51 CET je André Przywara napisal(a): > On 09/12/2020 14:33, Clément Péron wrote: > > Hi, > > > I try to review this, and compare against the vendor Kernel> > > > > On Wed, 2 Dec 2020 at 14:54, Andre Przywara <andre.przywara@arm.com> wrote: > >> While the clocks are fairly similar to the H6, many differ in tiny > >> details, so a separate clock driver seems indicated. > >> > >> Derived from the H6 clock driver, and adjusted according to the manual. > >> > >> Signed-off-by: Andre Przywara <andre.przywara@arm.com> > >> --- > >> > >> drivers/clk/sunxi-ng/Kconfig | 7 +- > >> drivers/clk/sunxi-ng/Makefile | 1 + > >> drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ > >> drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + > >> include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ > >> include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ > >> 6 files changed, 1376 insertions(+), 1 deletion(-) > >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c > >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h > >> create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h > >> create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h > >> > >> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig > >> index ce5f5847d5d3..cd46d8853876 100644 > >> --- a/drivers/clk/sunxi-ng/Kconfig > >> +++ b/drivers/clk/sunxi-ng/Kconfig > >> @@ -32,8 +32,13 @@ config SUN50I_H6_CCU > >> > >> default ARM64 && ARCH_SUNXI > >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > >> > >> +config SUN50I_H616_CCU > >> + bool "Support for the Allwinner H616 CCU" > >> + default ARM64 && ARCH_SUNXI > >> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > >> + > >> > >> config SUN50I_H6_R_CCU > >> > >> - bool "Support for the Allwinner H6 PRCM CCU" > >> + bool "Support for the Allwinner H6 and H616 PRCM CCU" > >> > >> default ARM64 && ARCH_SUNXI > >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > >> > >> diff --git a/drivers/clk/sunxi-ng/Makefile > >> b/drivers/clk/sunxi-ng/Makefile > >> index 3eb5cff40eac..96c324306d97 100644 > >> --- a/drivers/clk/sunxi-ng/Makefile > >> +++ b/drivers/clk/sunxi-ng/Makefile > >> @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o > >> > >> obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o > >> obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o > >> obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o > >> > >> +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o > >> > >> obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o > >> obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o > >> obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o > >> > >> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > >> b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c new file mode 100644 > >> index 000000000000..3fbb258f0354 > >> --- /dev/null > >> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > >> @@ -0,0 +1,1134 @@ > >> +// SPDX-License-Identifier: GPL-2.0 > >> +/* > >> + * Copyright (c) 2020 Arm Ltd. > >> + * Based on the H6 CCU driver, which is: > >> + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> > >> + */ > >> + > >> +#include <linux/clk-provider.h> > >> +#include <linux/io.h> > >> +#include <linux/of_address.h> > >> +#include <linux/platform_device.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-sun50i-h616.h" > >> + > >> +/* > >> + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However > >> + * P should only be used for output frequencies lower than 288 MHz. > >> + * > >> + * For now we can just model it as a multiplier clock, and force P to > >> /1. > >> + * > >> + * The M factor is present in the register's description, but not in the > >> + * frequency formula, and it's documented as "M is only used for > >> backdoor > >> + * testing", so it's not modelled and then force to 0. > >> + */ > >> +#define SUN50I_H616_PLL_CPUX_REG 0x000 > >> +static struct ccu_mult pll_cpux_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .common = { > >> + .reg = 0x000, > >> + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", > >> + &ccu_mult_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ > >> +#define SUN50I_H616_PLL_DDR0_REG 0x010 > >> +static struct ccu_nkmp pll_ddr0_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .common = { > >> + .reg = 0x010, > >> + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_DDR1_REG 0x018 > >> +static struct ccu_nkmp pll_ddr1_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .common = { > >> + .reg = 0x018, > >> + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 > >> +static struct ccu_nkmp pll_periph0_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .fixed_post_div = 4, > >> + .common = { > >> + .reg = 0x020, > >> + .features = CCU_FEATURE_FIXED_POSTDIV, > >> + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 > >> +static struct ccu_nkmp pll_periph1_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .fixed_post_div = 4, > >> + .common = { > >> + .reg = 0x028, > >> + .features = CCU_FEATURE_FIXED_POSTDIV, > >> + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_GPU_REG 0x030 > >> +static struct ccu_nkmp pll_gpu_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .common = { > >> + .reg = 0x030, > >> + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +/* > >> + * For Video PLLs, the output divider is described as "used for testing" > >> + * in the user manual. So it's not modelled and forced to 0. > >> + */ > >> +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 > >> +static struct ccu_nm pll_video0_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .fixed_post_div = 4, > >> + .min_rate = 288000000, > >> + .max_rate = 2400000000UL, > >> + .common = { > >> + .reg = 0x040, > >> + .features = CCU_FEATURE_FIXED_POSTDIV, > >> + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", > >> + &ccu_nm_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > > > > FYI the PLL video0 in your code is similar between H6/H616 but it's not > > the > > same in the vendor kernel. > > Vendor says for H6: > > pll_video0/pll_video1: 24*N/D1/4 > > for H616: > > pll_video0x4 24*N/D1 > > pll_video1/pll_video2: 24*N/D1/4 > > I don't see any particular problem with this? I mean we pretty surely > have the x4 clock on the H6, and for the H616 the manual agrees to your > findings? > > > I'm not sure if this comment is correct or not. > > > >> + > >> +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 > >> +static struct ccu_nm pll_video1_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .fixed_post_div = 4, > >> + .min_rate = 288000000, > >> + .max_rate = 2400000000UL, > >> + .common = { > >> + .reg = 0x048, > >> + .features = CCU_FEATURE_FIXED_POSTDIV, > >> + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", > >> + &ccu_nm_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 > >> +static struct ccu_nm pll_video2_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .fixed_post_div = 4, > >> + .min_rate = 288000000, > >> + .max_rate = 2400000000UL, > >> + .common = { > >> + .reg = 0x050, > >> + .features = CCU_FEATURE_FIXED_POSTDIV, > >> + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", > >> + &ccu_nm_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > > > > There is also a PLL_CSI. And all the CSI / LCD clocks but they are no > > output pins available in the H616. > > Maybe we can introduced these clocks later. > > I don't see good reasons to introduce undocumented and useless clocks at > this point. > So I will leave this out unless someone protests. I'm pretty sure that H616 datasheet describes only subset of functionality supported by die and BSP drivers cover full die functionality. Not only here, but everywhere. We can leave them out for now. > > >> + > >> +#define SUN50I_H616_PLL_VE_REG 0x058 > >> +static struct ccu_nkmp pll_ve_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .common = { > >> + .reg = 0x058, > >> + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +#define SUN50I_H616_PLL_DE_REG 0x060 > >> +static struct ccu_nkmp pll_de_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > >> + .common = { > >> + .reg = 0x060, > >> + .hw.init = CLK_HW_INIT("pll-de", "osc24M", > >> + &ccu_nkmp_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +/* > >> + * TODO: Determine SDM settings for the audio PLL. The manual suggests > >> + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b > >> + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, > >> + * pattern=0xe001288c for 22.5792 MHz. > >> + * This clashes with our fixed PLL_POST_DIV_P. > >> + */ > >> +#define SUN50I_H616_PLL_AUDIO_REG 0x078 > >> +static struct ccu_nm pll_audio_hs_clk = { > >> + .enable = BIT(31), > >> + .lock = BIT(28), > >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > >> + .common = { > >> + .reg = 0x078, > >> + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", > >> + &ccu_nm_ops, > >> + CLK_SET_RATE_UNGATE), > >> + }, > >> +}; > >> + > >> +static const char * const cpux_parents[] = { "osc24M", "osc32k", > >> + "iosc", "pll-cpux", "pll-periph0" > >> }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, > >> + 0x500, 24, 3, CLK_SET_RATE_PARENT | > >> CLK_IS_CRITICAL); > >> +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); > >> +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); > >> + > >> +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", > >> "osc32k", > >> + "iosc", > >> "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, > >> "psi-ahb1-ahb2", > >> + psi_ahb1_ahb2_parents, > >> + 0x510, > >> + 0, 2, /* M */ > >> + 8, 2, /* P */ > >> + 24, 2, /* mux */ > >> + 0); > >> + > >> +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", > >> "osc32k", > >> + "psi-ahb1-ahb2", > >> + "pll-periph0" }; > >> +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, > >> 0x51c, + 0, 2, /* M */ > >> + 8, 2, /* P */ > >> + 24, 2, /* mux */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, > >> 0x520, + 0, 2, /* M */ > >> + 8, 2, /* P */ > >> + 24, 2, /* mux */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, > >> 0x524, + 0, 2, /* M */ > >> + 8, 2, /* P */ > >> + 24, 2, /* mux */ > >> + 0); > >> + > >> +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", > >> + "pll-ddr0", "pll-ddr1" }; > >> +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, > >> + 0, 3, /* M */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_IS_CRITICAL); > >> + > >> +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; > >> +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, > >> + 0, 4, /* M */ > >> + 24, 1, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> + > >> +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", > >> + 0x60c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", > >> + de_parents, > >> + 0x620, > >> + 0, 4, /* M */ > >> + 24, 1, /* mux */ > >> + BIT(31), /* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", > >> "psi-ahb1-ahb2", + 0x62c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, > >> + 0, 4, /* M */ > >> + 24, 1, /* mux */ > >> + BIT(31), /* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", > >> + 0x63c, BIT(0), 0); > >> + > >> +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; > >> +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, > >> + 0, 2, /* M */ > >> + 24, 1, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, > >> + 0, 3, /* M */ > > > > M here should be 0,2 > > Right, good catch. > > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", > >> + 0x67c, BIT(0), 0); > >> + > >> +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, > >> + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 1, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", > >> + 0x68c, BIT(0), 0); > >> + > >> +static const char * const ve_parents[] = { "pll-ve" }; > >> +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, > >> + 0, 3, /* M */ > >> + 24, 1, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> + > >> +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", > >> + 0x69c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", > >> + 0x70c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", > >> + 0x73c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", > >> + 0x78c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", > >> + 0x79c, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), > >> 0); + > >> +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; > >> +static struct ccu_div dram_clk = { > >> + .div = _SUNXI_CCU_DIV(0, 2), > >> + .mux = _SUNXI_CCU_MUX(24, 2), > >> + .common = { > >> + .reg = 0x800, > >> + .hw.init = CLK_HW_INIT_PARENTS("dram", > >> + dram_parents, > >> + &ccu_div_ops, > >> + CLK_IS_CRITICAL), > >> + }, > >> +}; > >> + > >> +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", > >> + 0x804, BIT(0), 0); > >> +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", > >> + 0x804, BIT(1), 0); > >> +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", > >> + 0x804, BIT(2), 0); > >> +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", > >> + 0x804, BIT(3), 0); > >> +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", > >> + 0x804, BIT(5), 0); > > > > Compare to H6, you drop mbus-deinterlace but it is present in the vendor > > kernel. > It's not in the manual (which is what I look at). Not sure I can trust > the vendor kernel more here. This would need some experimenting. Best regards, Jernej > > >> +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", > >> + 0x804, BIT(10), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", > >> + 0x80c, BIT(0), CLK_IS_CRITICAL); > >> + > >> +static const char * const nand_spi_parents[] = { "osc24M", > >> "pll-periph0", > >> + "pll-periph1", > >> "pll-periph0-2x", + > >> "pll-periph1-2x" }; > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, > >> 0x810, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 3, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, > >> 0x814, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 3, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), > >> 0); > >> + > >> +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", > >> + "pll-periph1-2x" }; > >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, > >> 0x830, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + 2, /* post-div */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, > >> 0x834, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + 2, /* post-div */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, > >> 0x838, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + 2, /* post-div */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), > >> 0); > >> +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), > >> 0); > >> +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), > >> 0); > >> + > >> +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), > >> 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, > >> BIT(1), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", > >> 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", > >> "apb2", 0x90c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, > >> "bus-uart4", "apb2", 0x90c, BIT(4), 0); +static > >> SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); + > >> +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), > >> 0); > >> +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), > >> 0); > >> +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), > >> 0); > >> +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), > >> 0); > >> +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), > >> 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, > >> 0x940, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 3, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, > >> 0x944, + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 3, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), > >> 0); > >> +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), > >> 0); > >> + > >> +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, > >> + BIT(31) | BIT(30), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), > >> 0); +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, > >> BIT(1), 0); + > >> +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, > >> + 0, 4, /* M */ > >> + 8, 2, /* N */ > >> + 24, 1, /* mux */ > >> + BIT(31),/* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); > >> + > >> +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); > >> + > >> +static const char * const audio_parents[] = { "pll-audio-1x", > >> "pll-audio-2x", + > >> "pll-audio-4x", "pll-audio-hs" }; +static struct ccu_div spdif_clk = { > >> + .enable = BIT(31), > >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > >> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, > >> 2), > >> + .common = { > >> + .reg = 0xa20, > >> + .hw.init = CLK_HW_INIT_PARENTS("spdif", > >> + audio_parents, > >> + &ccu_div_ops, > >> + 0), > >> + }, > >> +}; > >> + > >> +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), > >> 0); + > >> +static struct ccu_div dmic_clk = { > >> + .enable = BIT(31), > >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > >> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, > >> 2), > >> + .common = { > >> + .reg = 0xa40, > >> + .hw.init = CLK_HW_INIT_PARENTS("dmic", > >> + audio_parents, > >> + &ccu_div_ops, > >> + 0), > >> + }, > >> +}; > >> + > >> +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), > >> 0); > >> + > >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", > >> + audio_parents, 0xa50, > >> + 0, 4, /* M */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", > >> + audio_parents, 0xa54, > >> + 0, 4, /* M */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> + > >> +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", > >> 0xa5c, + BIT(0), 0); > >> + > >> +static struct ccu_div audio_hub_clk = { > >> + .enable = BIT(31), > >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > >> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, > >> 2), > >> + .common = { > >> + .reg = 0xa60, > >> + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", > >> + audio_parents, > >> + &ccu_div_ops, > >> + 0), > >> + }, > >> +}; > >> + > >> +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, > >> BIT(0), 0); + > >> +/* > >> + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. > >> + * We will force them to 0 (12M divided from 48M). > >> + */ > >> +#define SUN50I_H616_USB0_CLK_REG 0xa70 > >> +#define SUN50I_H616_USB1_CLK_REG 0xa74 > >> +#define SUN50I_H616_USB2_CLK_REG 0xa78 > >> +#define SUN50I_H616_USB3_CLK_REG 0xa7c > >> + > >> +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, > >> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", > >> 0xa70, BIT(29), 0); + > >> +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, > >> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", > >> 0xa74, BIT(29), 0); + > >> +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, > >> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", > >> 0xa78, BIT(29), 0); + > >> +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, > >> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", > >> 0xa7c, BIT(29), 0); + > >> +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), > >> 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, > >> BIT(1), 0); +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", > >> 0xa8c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", > >> "ahb3", 0xa8c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, > >> "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); +static > >> SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); > >> +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, > >> BIT(6), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", > >> 0xa8c, BIT(7), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", > >> "ahb3", 0xa8c, BIT(8), 0); + > >> +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, > >> BIT(0), 0); + > >> +static struct clk_fixed_factor pll_periph0_4x_clk; > >> + > >> +static const char * const hdmi_parents[] = { "pll-video0", > >> "pll-video0-4x", + > >> "pll-video2", "pll-video2-4x" }; +static > >> SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, + > >> 0, 4, /* M */ > >> + 24, 2, /* mux */ > >> + BIT(31), /* gate */ > >> + 0); > >> + > >> +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, > >> BIT(31), 0); + > >> +static const char * const hdmi_cec_parents[] = { "osc32k", > >> "pll-periph0-2x" }; +static const struct ccu_mux_fixed_prediv > >> hdmi_cec_predivs[] = { > >> + { .index = 1, .div = 36621 }, > >> +}; > >> + > >> +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 > >> +static struct ccu_mux hdmi_cec_clk = { > >> + .enable = BIT(31), > >> + > >> + .mux = { > >> + .shift = 24, > >> + .width = 2, > >> + > >> + .fixed_predivs = hdmi_cec_predivs, > >> + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), > >> + }, > >> + > >> + .common = { > >> + .reg = 0xb10, > >> + .features = CCU_FEATURE_VARIABLE_PREDIV, > >> + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", > >> + hdmi_cec_parents, > >> + &ccu_mux_ops, > >> + 0), > >> + }, > >> +}; > >> + > >> +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), > >> 0); > >> + > >> +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", > >> + 0xb5c, BIT(0), 0); > >> + > >> +static const char * const tcon_tv0_parents[] = { "pll-video0", > >> + "pll-video0-4x", > >> + "pll-video1", > >> + "pll-video1-4x" }; > >> +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", > >> + tcon_tv0_parents, 0xb80, > >> + 0, 4, /* M */ > >> + 8, 2, /* P */ > >> + 24, 3, /* mux */ > >> + BIT(31), /* gate */ > >> + CLK_SET_RATE_PARENT); > >> + > >> +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", > >> + 0xb9c, BIT(0), 0); > > > > The TV1 clk is missing here > > Right, and some more TV encoder related. > > Cheers, > Andre
On 09/12/2020 22:20, Jernej Škrabec wrote: > Dne sreda, 09. december 2020 ob 22:35:51 CET je André Przywara napisal(a): >> On 09/12/2020 14:33, Clément Péron wrote: >> >> Hi, >> >>> I try to review this, and compare against the vendor Kernel> >>> >>> On Wed, 2 Dec 2020 at 14:54, Andre Przywara <andre.przywara@arm.com> > wrote: >>>> While the clocks are fairly similar to the H6, many differ in tiny >>>> details, so a separate clock driver seems indicated. >>>> >>>> Derived from the H6 clock driver, and adjusted according to the manual. >>>> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com> >>>> --- >>>> >>>> drivers/clk/sunxi-ng/Kconfig | 7 +- >>>> drivers/clk/sunxi-ng/Makefile | 1 + >>>> drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ >>>> drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + >>>> include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ >>>> include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ >>>> 6 files changed, 1376 insertions(+), 1 deletion(-) >>>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c >>>> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h >>>> create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h >>>> create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h >>>> >>>> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig >>>> index ce5f5847d5d3..cd46d8853876 100644 >>>> --- a/drivers/clk/sunxi-ng/Kconfig >>>> +++ b/drivers/clk/sunxi-ng/Kconfig >>>> @@ -32,8 +32,13 @@ config SUN50I_H6_CCU >>>> >>>> default ARM64 && ARCH_SUNXI >>>> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >>>> >>>> +config SUN50I_H616_CCU >>>> + bool "Support for the Allwinner H616 CCU" >>>> + default ARM64 && ARCH_SUNXI >>>> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >>>> + >>>> >>>> config SUN50I_H6_R_CCU >>>> >>>> - bool "Support for the Allwinner H6 PRCM CCU" >>>> + bool "Support for the Allwinner H6 and H616 PRCM CCU" >>>> >>>> default ARM64 && ARCH_SUNXI >>>> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >>>> >>>> diff --git a/drivers/clk/sunxi-ng/Makefile >>>> b/drivers/clk/sunxi-ng/Makefile >>>> index 3eb5cff40eac..96c324306d97 100644 >>>> --- a/drivers/clk/sunxi-ng/Makefile >>>> +++ b/drivers/clk/sunxi-ng/Makefile >>>> @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o >>>> >>>> obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o >>>> obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o >>>> obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o >>>> >>>> +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o >>>> >>>> obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o >>>> obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o >>>> obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o >>>> >>>> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >>>> b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c new file mode 100644 >>>> index 000000000000..3fbb258f0354 >>>> --- /dev/null >>>> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >>>> @@ -0,0 +1,1134 @@ >>>> +// SPDX-License-Identifier: GPL-2.0 >>>> +/* >>>> + * Copyright (c) 2020 Arm Ltd. >>>> + * Based on the H6 CCU driver, which is: >>>> + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> >>>> + */ >>>> + >>>> +#include <linux/clk-provider.h> >>>> +#include <linux/io.h> >>>> +#include <linux/of_address.h> >>>> +#include <linux/platform_device.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-sun50i-h616.h" >>>> + >>>> +/* >>>> + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However >>>> + * P should only be used for output frequencies lower than 288 MHz. >>>> + * >>>> + * For now we can just model it as a multiplier clock, and force P to >>>> /1. >>>> + * >>>> + * The M factor is present in the register's description, but not in the >>>> + * frequency formula, and it's documented as "M is only used for >>>> backdoor >>>> + * testing", so it's not modelled and then force to 0. >>>> + */ >>>> +#define SUN50I_H616_PLL_CPUX_REG 0x000 >>>> +static struct ccu_mult pll_cpux_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .common = { >>>> + .reg = 0x000, >>>> + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", >>>> + &ccu_mult_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ >>>> +#define SUN50I_H616_PLL_DDR0_REG 0x010 >>>> +static struct ccu_nkmp pll_ddr0_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .common = { >>>> + .reg = 0x010, >>>> + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_DDR1_REG 0x018 >>>> +static struct ccu_nkmp pll_ddr1_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .common = { >>>> + .reg = 0x018, >>>> + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 >>>> +static struct ccu_nkmp pll_periph0_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .fixed_post_div = 4, >>>> + .common = { >>>> + .reg = 0x020, >>>> + .features = CCU_FEATURE_FIXED_POSTDIV, >>>> + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 >>>> +static struct ccu_nkmp pll_periph1_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .fixed_post_div = 4, >>>> + .common = { >>>> + .reg = 0x028, >>>> + .features = CCU_FEATURE_FIXED_POSTDIV, >>>> + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_GPU_REG 0x030 >>>> +static struct ccu_nkmp pll_gpu_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .common = { >>>> + .reg = 0x030, >>>> + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +/* >>>> + * For Video PLLs, the output divider is described as "used for testing" >>>> + * in the user manual. So it's not modelled and forced to 0. >>>> + */ >>>> +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 >>>> +static struct ccu_nm pll_video0_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .fixed_post_div = 4, >>>> + .min_rate = 288000000, >>>> + .max_rate = 2400000000UL, >>>> + .common = { >>>> + .reg = 0x040, >>>> + .features = CCU_FEATURE_FIXED_POSTDIV, >>>> + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", >>>> + &ccu_nm_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>> >>> FYI the PLL video0 in your code is similar between H6/H616 but it's not >>> the >>> same in the vendor kernel. >>> Vendor says for H6: >>> pll_video0/pll_video1: 24*N/D1/4 >>> for H616: >>> pll_video0x4 24*N/D1 >>> pll_video1/pll_video2: 24*N/D1/4 >> >> I don't see any particular problem with this? I mean we pretty surely >> have the x4 clock on the H6, and for the H616 the manual agrees to your >> findings? >> >>> I'm not sure if this comment is correct or not. >>> >>>> + >>>> +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 >>>> +static struct ccu_nm pll_video1_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .fixed_post_div = 4, >>>> + .min_rate = 288000000, >>>> + .max_rate = 2400000000UL, >>>> + .common = { >>>> + .reg = 0x048, >>>> + .features = CCU_FEATURE_FIXED_POSTDIV, >>>> + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", >>>> + &ccu_nm_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 >>>> +static struct ccu_nm pll_video2_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .fixed_post_div = 4, >>>> + .min_rate = 288000000, >>>> + .max_rate = 2400000000UL, >>>> + .common = { >>>> + .reg = 0x050, >>>> + .features = CCU_FEATURE_FIXED_POSTDIV, >>>> + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", >>>> + &ccu_nm_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>> >>> There is also a PLL_CSI. And all the CSI / LCD clocks but they are no >>> output pins available in the H616. >>> Maybe we can introduced these clocks later. >> >> I don't see good reasons to introduce undocumented and useless clocks at >> this point. >> So I will leave this out unless someone protests. > > I'm pretty sure that H616 datasheet describes only subset of functionality > supported by die and BSP drivers cover full die functionality. Yeah, Clément found a comment in the BSP U-Boot that suggests that the same die is used with different packages. The H700 is mentioned as a sun50iw9p1 there as well, and this one supports LCD, reportedly. > Not only here, > but everywhere. We can leave them out for now. Right, we can add them later, maybe using a new clock compatible, like we do for the H3/H5. Cheers, Andre >>>> + >>>> +#define SUN50I_H616_PLL_VE_REG 0x058 >>>> +static struct ccu_nkmp pll_ve_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .common = { >>>> + .reg = 0x058, >>>> + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_PLL_DE_REG 0x060 >>>> +static struct ccu_nkmp pll_de_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >>>> + .common = { >>>> + .reg = 0x060, >>>> + .hw.init = CLK_HW_INIT("pll-de", "osc24M", >>>> + &ccu_nkmp_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +/* >>>> + * TODO: Determine SDM settings for the audio PLL. The manual suggests >>>> + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b >>>> + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, >>>> + * pattern=0xe001288c for 22.5792 MHz. >>>> + * This clashes with our fixed PLL_POST_DIV_P. >>>> + */ >>>> +#define SUN50I_H616_PLL_AUDIO_REG 0x078 >>>> +static struct ccu_nm pll_audio_hs_clk = { >>>> + .enable = BIT(31), >>>> + .lock = BIT(28), >>>> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >>>> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >>>> + .common = { >>>> + .reg = 0x078, >>>> + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", >>>> + &ccu_nm_ops, >>>> + CLK_SET_RATE_UNGATE), >>>> + }, >>>> +}; >>>> + >>>> +static const char * const cpux_parents[] = { "osc24M", "osc32k", >>>> + "iosc", "pll-cpux", "pll-periph0" >>>> }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, >>>> + 0x500, 24, 3, CLK_SET_RATE_PARENT | >>>> CLK_IS_CRITICAL); >>>> +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); >>>> +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); >>>> + >>>> +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", >>>> "osc32k", >>>> + "iosc", >>>> "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, >>>> "psi-ahb1-ahb2", >>>> + psi_ahb1_ahb2_parents, >>>> + 0x510, >>>> + 0, 2, /* M */ >>>> + 8, 2, /* P */ >>>> + 24, 2, /* mux */ >>>> + 0); >>>> + >>>> +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", >>>> "osc32k", >>>> + "psi-ahb1-ahb2", >>>> + "pll-periph0" }; >>>> +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, >>>> 0x51c, + 0, 2, /* M */ >>>> + 8, 2, /* P */ >>>> + 24, 2, /* mux */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, >>>> 0x520, + 0, 2, /* M */ >>>> + 8, 2, /* P */ >>>> + 24, 2, /* mux */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, >>>> 0x524, + 0, 2, /* M */ >>>> + 8, 2, /* P */ >>>> + 24, 2, /* mux */ >>>> + 0); >>>> + >>>> +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", >>>> + "pll-ddr0", "pll-ddr1" }; >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, >>>> + 0, 3, /* M */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_IS_CRITICAL); >>>> + >>>> +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, >>>> + 0, 4, /* M */ >>>> + 24, 1, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> + >>>> +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", >>>> + 0x60c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", >>>> + de_parents, >>>> + 0x620, >>>> + 0, 4, /* M */ >>>> + 24, 1, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", >>>> "psi-ahb1-ahb2", + 0x62c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, >>>> + 0, 4, /* M */ >>>> + 24, 1, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", >>>> + 0x63c, BIT(0), 0); >>>> + >>>> +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, >>>> + 0, 2, /* M */ >>>> + 24, 1, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, >>>> + 0, 3, /* M */ >>> >>> M here should be 0,2 >> >> Right, good catch. >> >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", >>>> + 0x67c, BIT(0), 0); >>>> + >>>> +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, >>>> + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 1, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", >>>> + 0x68c, BIT(0), 0); >>>> + >>>> +static const char * const ve_parents[] = { "pll-ve" }; >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, >>>> + 0, 3, /* M */ >>>> + 24, 1, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> + >>>> +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", >>>> + 0x69c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", >>>> + 0x70c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", >>>> + 0x73c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", >>>> + 0x78c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", >>>> + 0x79c, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), >>>> 0); + >>>> +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; >>>> +static struct ccu_div dram_clk = { >>>> + .div = _SUNXI_CCU_DIV(0, 2), >>>> + .mux = _SUNXI_CCU_MUX(24, 2), >>>> + .common = { >>>> + .reg = 0x800, >>>> + .hw.init = CLK_HW_INIT_PARENTS("dram", >>>> + dram_parents, >>>> + &ccu_div_ops, >>>> + CLK_IS_CRITICAL), >>>> + }, >>>> +}; >>>> + >>>> +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", >>>> + 0x804, BIT(0), 0); >>>> +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", >>>> + 0x804, BIT(1), 0); >>>> +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", >>>> + 0x804, BIT(2), 0); >>>> +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", >>>> + 0x804, BIT(3), 0); >>>> +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", >>>> + 0x804, BIT(5), 0); >>> >>> Compare to H6, you drop mbus-deinterlace but it is present in the vendor >>> kernel. >> It's not in the manual (which is what I look at). Not sure I can trust >> the vendor kernel more here. > > This would need some experimenting. > > Best regards, > Jernej > >> >>>> +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", >>>> + 0x804, BIT(10), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", >>>> + 0x80c, BIT(0), CLK_IS_CRITICAL); >>>> + >>>> +static const char * const nand_spi_parents[] = { "osc24M", >>>> "pll-periph0", >>>> + "pll-periph1", >>>> "pll-periph0-2x", + >>>> "pll-periph1-2x" }; >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, >>>> 0x810, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 3, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, >>>> 0x814, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 3, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), >>>> 0); >>>> + >>>> +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", >>>> + "pll-periph1-2x" }; >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, >>>> 0x830, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 2, /* post-div */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, >>>> 0x834, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 2, /* post-div */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, >>>> 0x838, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 2, /* post-div */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), >>>> 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), >>>> 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, >>>> BIT(1), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", >>>> 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", >>>> "apb2", 0x90c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, >>>> "bus-uart4", "apb2", 0x90c, BIT(4), 0); +static >>>> SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); + >>>> +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), >>>> 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, >>>> 0x940, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 3, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, >>>> 0x944, + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 3, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), >>>> 0); >>>> +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), >>>> 0); >>>> + >>>> +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, >>>> + BIT(31) | BIT(30), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), >>>> 0); +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, >>>> BIT(1), 0); + >>>> +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, >>>> + 0, 4, /* M */ >>>> + 8, 2, /* N */ >>>> + 24, 1, /* mux */ >>>> + BIT(31),/* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); >>>> + >>>> +static const char * const audio_parents[] = { "pll-audio-1x", >>>> "pll-audio-2x", + >>>> "pll-audio-4x", "pll-audio-hs" }; +static struct ccu_div spdif_clk = { >>>> + .enable = BIT(31), >>>> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >>>> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, >>>> 2), >>>> + .common = { >>>> + .reg = 0xa20, >>>> + .hw.init = CLK_HW_INIT_PARENTS("spdif", >>>> + audio_parents, >>>> + &ccu_div_ops, >>>> + 0), >>>> + }, >>>> +}; >>>> + >>>> +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), >>>> 0); + >>>> +static struct ccu_div dmic_clk = { >>>> + .enable = BIT(31), >>>> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >>>> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, >>>> 2), >>>> + .common = { >>>> + .reg = 0xa40, >>>> + .hw.init = CLK_HW_INIT_PARENTS("dmic", >>>> + audio_parents, >>>> + &ccu_div_ops, >>>> + 0), >>>> + }, >>>> +}; >>>> + >>>> +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), >>>> 0); >>>> + >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", >>>> + audio_parents, 0xa50, >>>> + 0, 4, /* M */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", >>>> + audio_parents, 0xa54, >>>> + 0, 4, /* M */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> + >>>> +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", >>>> 0xa5c, + BIT(0), 0); >>>> + >>>> +static struct ccu_div audio_hub_clk = { >>>> + .enable = BIT(31), >>>> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >>>> CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, >>>> 2), >>>> + .common = { >>>> + .reg = 0xa60, >>>> + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", >>>> + audio_parents, >>>> + &ccu_div_ops, >>>> + 0), >>>> + }, >>>> +}; >>>> + >>>> +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, >>>> BIT(0), 0); + >>>> +/* >>>> + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. >>>> + * We will force them to 0 (12M divided from 48M). >>>> + */ >>>> +#define SUN50I_H616_USB0_CLK_REG 0xa70 >>>> +#define SUN50I_H616_USB1_CLK_REG 0xa74 >>>> +#define SUN50I_H616_USB2_CLK_REG 0xa78 >>>> +#define SUN50I_H616_USB3_CLK_REG 0xa7c >>>> + >>>> +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, >>>> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", >>>> 0xa70, BIT(29), 0); + >>>> +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, >>>> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", >>>> 0xa74, BIT(29), 0); + >>>> +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, >>>> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", >>>> 0xa78, BIT(29), 0); + >>>> +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, >>>> BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", >>>> 0xa7c, BIT(29), 0); + >>>> +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), >>>> 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, >>>> BIT(1), 0); +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", >>>> 0xa8c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", >>>> "ahb3", 0xa8c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, >>>> "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); +static >>>> SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); >>>> +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, >>>> BIT(6), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", >>>> 0xa8c, BIT(7), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", >>>> "ahb3", 0xa8c, BIT(8), 0); + >>>> +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, >>>> BIT(0), 0); + >>>> +static struct clk_fixed_factor pll_periph0_4x_clk; >>>> + >>>> +static const char * const hdmi_parents[] = { "pll-video0", >>>> "pll-video0-4x", + >>>> "pll-video2", "pll-video2-4x" }; +static >>>> SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, + >>>> 0, 4, /* M */ >>>> + 24, 2, /* mux */ >>>> + BIT(31), /* gate */ >>>> + 0); >>>> + >>>> +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, >>>> BIT(31), 0); + >>>> +static const char * const hdmi_cec_parents[] = { "osc32k", >>>> "pll-periph0-2x" }; +static const struct ccu_mux_fixed_prediv >>>> hdmi_cec_predivs[] = { >>>> + { .index = 1, .div = 36621 }, >>>> +}; >>>> + >>>> +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 >>>> +static struct ccu_mux hdmi_cec_clk = { >>>> + .enable = BIT(31), >>>> + >>>> + .mux = { >>>> + .shift = 24, >>>> + .width = 2, >>>> + >>>> + .fixed_predivs = hdmi_cec_predivs, >>>> + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), >>>> + }, >>>> + >>>> + .common = { >>>> + .reg = 0xb10, >>>> + .features = CCU_FEATURE_VARIABLE_PREDIV, >>>> + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", >>>> + hdmi_cec_parents, >>>> + &ccu_mux_ops, >>>> + 0), >>>> + }, >>>> +}; >>>> + >>>> +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), >>>> 0); >>>> + >>>> +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", >>>> + 0xb5c, BIT(0), 0); >>>> + >>>> +static const char * const tcon_tv0_parents[] = { "pll-video0", >>>> + "pll-video0-4x", >>>> + "pll-video1", >>>> + "pll-video1-4x" }; >>>> +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", >>>> + tcon_tv0_parents, 0xb80, >>>> + 0, 4, /* M */ >>>> + 8, 2, /* P */ >>>> + 24, 3, /* mux */ >>>> + BIT(31), /* gate */ >>>> + CLK_SET_RATE_PARENT); >>>> + >>>> +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", >>>> + 0xb9c, BIT(0), 0); >>> >>> The TV1 clk is missing here >> >> Right, and some more TV encoder related. >> >> Cheers, >> Andre > > > > >
在 2020-12-02星期三的 13:54 +0000,Andre Przywara写道: > While the clocks are fairly similar to the H6, many differ in tiny > details, so a separate clock driver seems indicated. > > Derived from the H6 clock driver, and adjusted according to the > manual. > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > --- > drivers/clk/sunxi-ng/Kconfig | 7 +- > drivers/clk/sunxi-ng/Makefile | 1 + > drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 > +++++++++++++++++++ > drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + > include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ > include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ > 6 files changed, 1376 insertions(+), 1 deletion(-) > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c > create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h > create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h > create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h > > diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi- > ng/Kconfig > index ce5f5847d5d3..cd46d8853876 100644 > --- a/drivers/clk/sunxi-ng/Kconfig > +++ b/drivers/clk/sunxi-ng/Kconfig > @@ -32,8 +32,13 @@ config SUN50I_H6_CCU > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > +config SUN50I_H616_CCU > + bool "Support for the Allwinner H616 CCU" > + default ARM64 && ARCH_SUNXI > + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > + > config SUN50I_H6_R_CCU > - bool "Support for the Allwinner H6 PRCM CCU" > + bool "Support for the Allwinner H6 and H616 PRCM CCU" > default ARM64 && ARCH_SUNXI > depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST > > diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi- > ng/Makefile > index 3eb5cff40eac..96c324306d97 100644 > --- a/drivers/clk/sunxi-ng/Makefile > +++ b/drivers/clk/sunxi-ng/Makefile > @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i- > a64.o > obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o > obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o > obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o > +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o > obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o > obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o > obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > new file mode 100644 > index 000000000000..3fbb258f0354 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c > @@ -0,0 +1,1134 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2020 Arm Ltd. > + * Based on the H6 CCU driver, which is: > + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/io.h> > +#include <linux/of_address.h> > +#include <linux/platform_device.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-sun50i-h616.h" > + > +/* > + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. > However > + * P should only be used for output frequencies lower than 288 MHz. > + * > + * For now we can just model it as a multiplier clock, and force P > to /1. > + * > + * The M factor is present in the register's description, but not in > the > + * frequency formula, and it's documented as "M is only used for > backdoor > + * testing", so it's not modelled and then force to 0. > + */ > +#define SUN50I_H616_PLL_CPUX_REG 0x000 > +static struct ccu_mult pll_cpux_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .common = { > + .reg = 0x000, > + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", > + &ccu_mult_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K > */ > +#define SUN50I_H616_PLL_DDR0_REG 0x010 > +static struct ccu_nkmp pll_ddr0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x010, > + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DDR1_REG 0x018 > +static struct ccu_nkmp pll_ddr1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x018, > + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 > +static struct ccu_nkmp pll_periph0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, Isn't it 2 here? The user manual says: ``` PLL_PERI0(2X) = 24 MHz*N/M0/M1 PLL_PERI0(1X) = 24 MHz*N/M0/M1/2 ``` + .common = { > + .reg = 0x020, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 > +static struct ccu_nkmp pll_periph1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .fixed_post_div = 4, > + .common = { > + .reg = 0x028, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_GPU_REG 0x030 > +static struct ccu_nkmp pll_gpu_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x030, > + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * For Video PLLs, the output divider is described as "used for > testing" > + * in the user manual. So it's not modelled and forced to 0. > + */ > +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 > +static struct ccu_nm pll_video0_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x040, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 > +static struct ccu_nm pll_video1_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x048, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 > +static struct ccu_nm pll_video2_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .fixed_post_div = 4, > + .min_rate = 288000000, > + .max_rate = 2400000000UL, > + .common = { > + .reg = 0x050, > + .features = CCU_FEATURE_FIXED_POSTDIV, > + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_VE_REG 0x058 > +static struct ccu_nkmp pll_ve_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x058, > + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +#define SUN50I_H616_PLL_DE_REG 0x060 > +static struct ccu_nkmp pll_de_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ > + .common = { > + .reg = 0x060, > + .hw.init = CLK_HW_INIT("pll-de", "osc24M", > + &ccu_nkmp_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +/* > + * TODO: Determine SDM settings for the audio PLL. The manual > suggests > + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, > pattern=0xe000c49b > + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, > OUTPUT_DIV=2, > + * pattern=0xe001288c for 22.5792 MHz. > + * This clashes with our fixed PLL_POST_DIV_P. > + */ > +#define SUN50I_H616_PLL_AUDIO_REG 0x078 > +static struct ccu_nm pll_audio_hs_clk = { > + .enable = BIT(31), > + .lock = BIT(28), > + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), > + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ > + .common = { > + .reg = 0x078, > + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", > + &ccu_nm_ops, > + CLK_SET_RATE_UNGATE), > + }, > +}; > + > +static const char * const cpux_parents[] = { "osc24M", "osc32k", > + "iosc", "pll-cpux", "pll- > periph0" }; > +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, > + 0x500, 24, 3, CLK_SET_RATE_PARENT | > CLK_IS_CRITICAL); > +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); > +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, > 0); > + > +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", > "osc32k", > + "iosc", "pll- > periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", > + psi_ahb1_ahb2_parents, > + 0x510, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", > "osc32k", > + "psi-ahb1-ahb2", > + "pll-periph0" }; > +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", > ahb3_apb1_apb2_parents, 0x51c, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", > ahb3_apb1_apb2_parents, 0x520, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", > ahb3_apb1_apb2_parents, 0x524, > + 0, 2, /* M */ > + 8, 2, /* P */ > + 24, 2, /* mux */ > + 0); > + > +static const char * const mbus_parents[] = { "osc24M", "pll-periph0- > 2x", > + "pll-ddr0", "pll-ddr1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, > 0x540, > + 0, 3, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_IS_CRITICAL); > + > +static const char * const de_parents[] = { "pll-de", "pll-periph0- > 2x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", > + 0x60c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", > + de_parents, > + 0x620, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi- > ahb1-ahb2", > + 0x62c, BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, > + 0, 4, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", > + 0x63c, BIT(0), 0); > + > +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, > 0x670, > + 0, 2, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", > 0x674, > + 0, 3, /* M */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", > + 0x67c, BIT(0), 0); > + > +static const char * const ce_parents[] = { "osc24M", "pll-periph0- > 2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", > + 0x68c, BIT(0), 0); > + > +static const char * const ve_parents[] = { "pll-ve" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, > + 0, 3, /* M */ > + 24, 1, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", > + 0x69c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", > + 0x70c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1- > ahb2", > + 0x73c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); > + > +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", > + 0x78c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", > + 0x79c, BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), > 0); > + > +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, > BIT(0), 0); > + > +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" > }; > +static struct ccu_div dram_clk = { > + .div = _SUNXI_CCU_DIV(0, 2), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0x800, > + .hw.init = CLK_HW_INIT_PARENTS("dram", > + dram_parents, > + &ccu_div_ops, > + CLK_IS_CRITICAL), > + }, > +}; > + > +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", > + 0x804, BIT(0), 0); > +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", > + 0x804, BIT(1), 0); > +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", > + 0x804, BIT(2), 0); > +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", > + 0x804, BIT(3), 0); > +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", > + 0x804, BIT(5), 0); > +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", > + 0x804, BIT(10), 0); > + > +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", > + 0x80c, BIT(0), CLK_IS_CRITICAL); > + > +static const char * const nand_spi_parents[] = { "osc24M", "pll- > periph0", > + "pll-periph1", "pll- > periph0-2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", > nand_spi_parents, 0x810, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", > nand_spi_parents, 0x814, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, > BIT(0), 0); > + > +static const char * const mmc_parents[] = { "osc24M", "pll-periph0- > 2x", > + "pll-periph1-2x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", > mmc_parents, 0x830, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div > */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", > mmc_parents, 0x834, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div > */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", > mmc_parents, 0x838, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 2, /* post-div > */ > + 0); > + > +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, > BIT(1), 0); > +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, > BIT(2), 0); > + > +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, > BIT(1), 0); > +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, > BIT(2), 0); > +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, > BIT(3), 0); > +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, > BIT(4), 0); > +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, > BIT(5), 0); > + > +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, > BIT(1), 0); > +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, > BIT(2), 0); > +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, > BIT(3), 0); > +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, > BIT(4), 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", > nand_spi_parents, 0x940, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", > nand_spi_parents, 0x944, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 3, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, > BIT(1), 0); > + > +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, > + BIT(31) | BIT(30), 0); > + > +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, > BIT(1), 0); > + > +static const char * const ts_parents[] = { "osc24M", "pll-periph0" > }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, > + 0, 4, /* M */ > + 8, 2, /* N */ > + 24, 1, /* mux */ > + BIT(31),/* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), > 0); > + > +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), > 0); > + > +static const char * const audio_parents[] = { "pll-audio-1x", "pll- > audio-2x", > + "pll-audio-4x", "pll- > audio-hs" }; > +static struct ccu_div spdif_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa20, > + .hw.init = CLK_HW_INIT_PARENTS("spdif", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, > BIT(0), 0); > + > +static struct ccu_div dmic_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa40, > + .hw.init = CLK_HW_INIT_PARENTS("dmic", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, > BIT(0), 0); > + > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec- > 1x", > + audio_parents, 0xa50, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec- > 4x", > + audio_parents, 0xa54, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", > "apb1", 0xa5c, > + BIT(0), 0); > + > +static struct ccu_div audio_hub_clk = { > + .enable = BIT(31), > + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, > CLK_DIVIDER_POWER_OF_TWO), > + .mux = _SUNXI_CCU_MUX(24, 2), > + .common = { > + .reg = 0xa60, > + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", > + audio_parents, > + &ccu_div_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", > 0xa6c, BIT(0), 0); > + > +/* > + * There are OHCI 12M clock source selection bits for 2 USB 2.0 > ports. > + * We will force them to 0 (12M divided from 48M). > + */ > +#define SUN50I_H616_USB0_CLK_REG 0xa70 > +#define SUN50I_H616_USB1_CLK_REG 0xa74 > +#define SUN50I_H616_USB2_CLK_REG 0xa78 > +#define SUN50I_H616_USB3_CLK_REG 0xa7c > + > +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, > BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, > BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, > BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, > BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, > BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, > BIT(29), 0); > + > +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, > BIT(31), 0); > +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, > BIT(29), 0); > + > +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, > BIT(0), 0); > +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, > BIT(1), 0); > +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, > BIT(2), 0); > +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, > BIT(3), 0); > +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, > BIT(4), 0); > +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, > BIT(5), 0); > +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, > BIT(6), 0); > +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, > BIT(7), 0); > +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), > 0); > + > +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, > BIT(0), 0); > + > +static struct clk_fixed_factor pll_periph0_4x_clk; > + > +static const char * const hdmi_parents[] = { "pll-video0", "pll- > video0-4x", > + "pll-video2", "pll-video2- > 4x" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, > 0xb00, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, > BIT(31), 0); > + > +static const char * const hdmi_cec_parents[] = { "osc32k", "pll- > periph0-2x" }; > +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { > + { .index = 1, .div = 36621 }, > +}; > + > +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 > +static struct ccu_mux hdmi_cec_clk = { > + .enable = BIT(31), > + > + .mux = { > + .shift = 24, > + .width = 2, > + > + .fixed_predivs = hdmi_cec_predivs, > + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), > + }, > + > + .common = { > + .reg = 0xb10, > + .features = CCU_FEATURE_VARIABLE_PREDIV, > + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", > + hdmi_cec_parents, > + &ccu_mux_ops, > + 0), > + }, > +}; > + > +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, > BIT(0), 0); > + > +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", > + 0xb5c, BIT(0), 0); > + > +static const char * const tcon_tv0_parents[] = { "pll-video0", > + "pll-video0-4x", > + "pll-video1", > + "pll-video1-4x" }; > +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", > + tcon_tv0_parents, 0xb80, > + 0, 4, /* M */ > + 8, 2, /* P */ > + 24, 3, /* mux */ > + BIT(31), /* gate */ > + CLK_SET_RATE_PARENT); > + > +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", > + 0xb9c, BIT(0), 0); > + > +static const char * const hdcp_parents[] = { "pll-periph0", "pll- > periph1" }; > +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, > 0xc40, > + 0, 4, /* M */ > + 24, 2, /* mux */ > + BIT(31), /* gate */ > + 0); > + > +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, > BIT(0), 0); > + > +/* Fixed factor clocks */ > +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, > 0); > + > +static const struct clk_hw *clk_parent_pll_audio[] = { > + &pll_audio_hs_clk.common.hw > +}; > + > +/* > + * The divider of pll-audio is fixed to 24 for now, so 24576000 and > 22579200 > + * rates can be set exactly in conjunction with sigma-delta > modulation. > + */ > +static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", > + clk_parent_pll_audio, > + 96, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", > + clk_parent_pll_audio, > + 48, 1, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", > + clk_parent_pll_audio, > + 24, 1, CLK_SET_RATE_PARENT); > + > +static const struct clk_hw *pll_periph0_parents[] = { > + &pll_periph0_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x", > + pll_periph0_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x", > + pll_periph0_parents, > + 1, 2, 0); > + > +static const struct clk_hw *pll_periph1_parents[] = { > + &pll_periph1_clk.common.hw > +}; > +static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x", > + pll_periph1_parents, > + 1, 4, 0); > +static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x", > + pll_periph1_parents, > + 1, 2, 0); > + > +static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x", > + &pll_video0_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x", > + &pll_video1_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > +static CLK_FIXED_FACTOR_HW(pll_video2_4x_clk, "pll-video2-4x", > + &pll_video2_clk.common.hw, > + 1, 4, CLK_SET_RATE_PARENT); > + > +static struct ccu_common *sun50i_h616_ccu_clks[] = { > + &pll_cpux_clk.common, > + &pll_ddr0_clk.common, > + &pll_ddr1_clk.common, > + &pll_periph0_clk.common, > + &pll_periph1_clk.common, > + &pll_gpu_clk.common, > + &pll_video0_clk.common, > + &pll_video1_clk.common, > + &pll_video2_clk.common, > + &pll_ve_clk.common, > + &pll_de_clk.common, > + &pll_audio_hs_clk.common, > + &cpux_clk.common, > + &axi_clk.common, > + &cpux_apb_clk.common, > + &psi_ahb1_ahb2_clk.common, > + &ahb3_clk.common, > + &apb1_clk.common, > + &apb2_clk.common, > + &mbus_clk.common, > + &de_clk.common, > + &bus_de_clk.common, > + &deinterlace_clk.common, > + &bus_deinterlace_clk.common, > + &g2d_clk.common, > + &bus_g2d_clk.common, > + &gpu0_clk.common, > + &bus_gpu_clk.common, > + &gpu1_clk.common, > + &ce_clk.common, > + &bus_ce_clk.common, > + &ve_clk.common, > + &bus_ve_clk.common, > + &bus_dma_clk.common, > + &bus_hstimer_clk.common, > + &avs_clk.common, > + &bus_dbg_clk.common, > + &bus_psi_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_ts_clk.common, > + &mbus_nand_clk.common, > + &mbus_g2d_clk.common, > + &bus_dram_clk.common, > + &nand0_clk.common, > + &nand1_clk.common, > + &bus_nand_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_uart4_clk.common, > + &bus_uart5_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, > + &bus_spi0_clk.common, > + &bus_spi1_clk.common, > + &emac_25m_clk.common, > + &bus_emac0_clk.common, > + &bus_emac1_clk.common, > + &ts_clk.common, > + &bus_ts_clk.common, > + &bus_ths_clk.common, > + &spdif_clk.common, > + &bus_spdif_clk.common, > + &dmic_clk.common, > + &bus_dmic_clk.common, > + &audio_codec_1x_clk.common, > + &audio_codec_4x_clk.common, > + &bus_audio_codec_clk.common, > + &audio_hub_clk.common, > + &bus_audio_hub_clk.common, > + &usb_ohci0_clk.common, > + &usb_phy0_clk.common, > + &usb_ohci1_clk.common, > + &usb_phy1_clk.common, > + &usb_ohci2_clk.common, > + &usb_phy2_clk.common, > + &usb_ohci3_clk.common, > + &usb_phy3_clk.common, > + &bus_ohci0_clk.common, > + &bus_ohci1_clk.common, > + &bus_ohci2_clk.common, > + &bus_ohci3_clk.common, > + &bus_ehci0_clk.common, > + &bus_ehci1_clk.common, > + &bus_ehci2_clk.common, > + &bus_ehci3_clk.common, > + &bus_otg_clk.common, > + &bus_keyadc_clk.common, > + &hdmi_clk.common, > + &hdmi_slow_clk.common, > + &hdmi_cec_clk.common, > + &bus_hdmi_clk.common, > + &bus_tcon_top_clk.common, > + &tcon_tv0_clk.common, > + &bus_tcon_tv0_clk.common, > + &hdcp_clk.common, > + &bus_hdcp_clk.common, > +}; > + > +static struct clk_hw_onecell_data sun50i_h616_hw_clks = { > + .hws = { > + [CLK_OSC12M] = &osc12M_clk.hw, > + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, > + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, > + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, > + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, > + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, > + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, > + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, > + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, > + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, > + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, > + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, > + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, > + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, > + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, > + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, > + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, > + [CLK_PLL_VE] = &pll_ve_clk.common.hw, > + [CLK_PLL_DE] = &pll_de_clk.common.hw, > + [CLK_PLL_AUDIO_HS] = > &pll_audio_hs_clk.common.hw, > + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.hw, > + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, > + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, > + [CLK_CPUX] = &cpux_clk.common.hw, > + [CLK_AXI] = &axi_clk.common.hw, > + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, > + [CLK_PSI_AHB1_AHB2] = > &psi_ahb1_ahb2_clk.common.hw, > + [CLK_AHB3] = &ahb3_clk.common.hw, > + [CLK_APB1] = &apb1_clk.common.hw, > + [CLK_APB2] = &apb2_clk.common.hw, > + [CLK_MBUS] = &mbus_clk.common.hw, > + [CLK_DE] = &de_clk.common.hw, > + [CLK_BUS_DE] = &bus_de_clk.common.hw, > + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, > + [CLK_BUS_DEINTERLACE] = > &bus_deinterlace_clk.common.hw, > + [CLK_G2D] = &g2d_clk.common.hw, > + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, > + [CLK_GPU0] = &gpu0_clk.common.hw, > + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, > + [CLK_GPU1] = &gpu1_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_BUS_DMA] = &bus_dma_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_PSI] = &bus_psi_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_TS] = &mbus_ts_clk.common.hw, > + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, > + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, > + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, > + [CLK_NAND0] = &nand0_clk.common.hw, > + [CLK_NAND1] = &nand1_clk.common.hw, > + [CLK_BUS_NAND] = &bus_nand_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_UART4] = &bus_uart4_clk.common.hw, > + [CLK_BUS_UART5] = &bus_uart5_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_BUS_SPI0] = &bus_spi0_clk.common.hw, > + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, > + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, > + [CLK_BUS_EMAC0] = &bus_emac0_clk.common.hw, > + [CLK_BUS_EMAC1] = &bus_emac1_clk.common.hw, > + [CLK_TS] = &ts_clk.common.hw, > + [CLK_BUS_TS] = &bus_ts_clk.common.hw, > + [CLK_BUS_THS] = &bus_ths_clk.common.hw, > + [CLK_SPDIF] = &spdif_clk.common.hw, > + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, > + [CLK_DMIC] = &dmic_clk.common.hw, > + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, > + [CLK_AUDIO_CODEC_1X] = > &audio_codec_1x_clk.common.hw, > + [CLK_AUDIO_CODEC_4X] = > &audio_codec_4x_clk.common.hw, > + [CLK_BUS_AUDIO_CODEC] = > &bus_audio_codec_clk.common.hw, > + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, > + [CLK_BUS_AUDIO_HUB] = > &bus_audio_hub_clk.common.hw, > + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, > + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, > + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, > + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, > + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, > + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, > + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, > + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, > + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, > + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, > + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, > + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, > + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, > + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, > + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, > + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, > + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, > + [CLK_BUS_KEYADC] = &bus_keyadc_clk.common.hw, > + [CLK_HDMI] = &hdmi_clk.common.hw, > + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, > + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, > + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, > + [CLK_BUS_TCON_TOP] = > &bus_tcon_top_clk.common.hw, > + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, > + [CLK_BUS_TCON_TV0] = > &bus_tcon_tv0_clk.common.hw, > + [CLK_HDCP] = &hdcp_clk.common.hw, > + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, > + }, > + .num = CLK_NUMBER, > +}; > + > +static struct ccu_reset_map sun50i_h616_ccu_resets[] = { > + [RST_MBUS] = { 0x540, BIT(30) }, > + > + [RST_BUS_DE] = { 0x60c, BIT(16) }, > + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, > + [RST_BUS_GPU] = { 0x67c, BIT(16) }, > + [RST_BUS_CE] = { 0x68c, BIT(16) }, > + [RST_BUS_VE] = { 0x69c, BIT(16) }, > + [RST_BUS_DMA] = { 0x70c, BIT(16) }, > + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, > + [RST_BUS_DBG] = { 0x78c, BIT(16) }, > + [RST_BUS_PSI] = { 0x79c, BIT(16) }, > + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, > + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, > + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, > + [RST_BUS_NAND] = { 0x82c, 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_UART4] = { 0x90c, BIT(20) }, > + [RST_BUS_UART5] = { 0x90c, BIT(21) }, > + [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_EMAC0] = { 0x97c, BIT(16) }, > + [RST_BUS_EMAC1] = { 0x97c, BIT(17) }, > + [RST_BUS_TS] = { 0x9bc, BIT(16) }, > + [RST_BUS_THS] = { 0x9fc, BIT(16) }, > + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, > + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, > + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, > + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, > + > + [RST_USB_PHY0] = { 0xa70, BIT(30) }, > + [RST_USB_PHY1] = { 0xa74, BIT(30) }, > + [RST_USB_PHY2] = { 0xa78, BIT(30) }, > + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, > + > + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, > + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, > + [RST_BUS_OHCI2] = { 0xa8c, BIT(18) }, > + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, > + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, > + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, > + [RST_BUS_EHCI2] = { 0xa8c, BIT(22) }, > + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, > + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, > + [RST_BUS_KEYADC] = { 0xa9c, BIT(16) }, > + > + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, > + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, > + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, > + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, > + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, > +}; > + > +static const struct sunxi_ccu_desc sun50i_h616_ccu_desc = { > + .ccu_clks = sun50i_h616_ccu_clks, > + .num_ccu_clks = ARRAY_SIZE(sun50i_h616_ccu_clks), > + > + .hw_clks = &sun50i_h616_hw_clks, > + > + .resets = sun50i_h616_ccu_resets, > + .num_resets = ARRAY_SIZE(sun50i_h616_ccu_resets), > +}; > + > +static const u32 pll_regs[] = { > + SUN50I_H616_PLL_CPUX_REG, > + SUN50I_H616_PLL_DDR0_REG, > + SUN50I_H616_PLL_DDR1_REG, > + SUN50I_H616_PLL_PERIPH0_REG, > + SUN50I_H616_PLL_PERIPH1_REG, > + SUN50I_H616_PLL_GPU_REG, > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > + SUN50I_H616_PLL_VE_REG, > + SUN50I_H616_PLL_DE_REG, > + SUN50I_H616_PLL_AUDIO_REG, > +}; > + > +static const u32 pll_video_regs[] = { > + SUN50I_H616_PLL_VIDEO0_REG, > + SUN50I_H616_PLL_VIDEO1_REG, > + SUN50I_H616_PLL_VIDEO2_REG, > +}; > + > +static const u32 usb2_clk_regs[] = { > + SUN50I_H616_USB0_CLK_REG, > + SUN50I_H616_USB1_CLK_REG, > + SUN50I_H616_USB2_CLK_REG, > + SUN50I_H616_USB3_CLK_REG, > +}; > + > +static int sun50i_h616_ccu_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + void __iomem *reg; > + u32 val; > + int i; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + reg = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(reg)) > + return PTR_ERR(reg); > + > + /* Enable the lock bits on all PLLs */ > + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { > + val = readl(reg + pll_regs[i]); > + val |= BIT(29); > + writel(val, reg + pll_regs[i]); > + } > + > + /* > + * Force the output divider of video PLLs to 0. > + * > + * See the comment before pll-video0 definition for the reason. > + */ > + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { > + val = readl(reg + pll_video_regs[i]); > + val &= ~BIT(0); > + writel(val, reg + pll_video_regs[i]); > + } > + > + /* > + * Force OHCI 12M clock sources to 00 (12MHz divided from > 48MHz) > + * > + * This clock mux is still mysterious, and the code just > enforces > + * it to have a valid clock parent. > + */ > + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { > + val = readl(reg + usb2_clk_regs[i]); > + val &= ~GENMASK(25, 24); > + writel (val, reg + usb2_clk_regs[i]); > + } > + > + /* > + * Force the post-divider of pll-audio to 12 and the output > divider > + * of it to 2, so 24576000 and 22579200 rates can be set > exactly. > + */ > + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); > + val &= ~(GENMASK(21, 16) | BIT(0)); > + writel(val | (11 << 16) | BIT(0), reg + > SUN50I_H616_PLL_AUDIO_REG); > + > + /* > + * First clock parent (osc32K) is unusable for CEC. But since > there > + * is no good way to force parent switch (both run with same > frequency), > + * just set second clock parent here. > + */ > + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + val |= BIT(24); > + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); > + > + return sunxi_ccu_probe(pdev->dev.of_node, reg, > &sun50i_h616_ccu_desc); > +} > + > +static const struct of_device_id sun50i_h616_ccu_ids[] = { > + { .compatible = "allwinner,sun50i-h616-ccu", > + .data = &sun50i_h616_ccu_desc }, > + { } > +}; > + > +static struct platform_driver sun50i_h616_ccu_driver = { > + .probe = sun50i_h616_ccu_probe, > + .driver = { > + .name = "sun50i-h616-ccu", > + .of_match_table = sun50i_h616_ccu_ids, > + }, > +}; > +builtin_platform_driver(sun50i_h616_ccu_driver); > diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > new file mode 100644 > index 000000000000..da8f0b1206f9 > --- /dev/null > +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h > @@ -0,0 +1,58 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright 2020 Arm Ltd. > + */ > + > +#ifndef _CCU_SUN50I_H616_H_ > +#define _CCU_SUN50I_H616_H_ > + > +#include <dt-bindings/clock/sun50i-h616-ccu.h> > +#include <dt-bindings/reset/sun50i-h616-ccu.h> > + > +#define CLK_OSC12M 0 > +#define CLK_PLL_CPUX 1 > +#define CLK_PLL_DDR0 2 > +#define CLK_PLL_DDR1 3 > + > +/* PLL_PERIPH0 exported for PRCM */ > + > +#define CLK_PLL_PERIPH0_2X 5 > +#define CLK_PLL_PERIPH0_4X 6 > +#define CLK_PLL_PERIPH1 7 > +#define CLK_PLL_PERIPH1_2X 8 > +#define CLK_PLL_PERIPH1_4X 9 > +#define CLK_PLL_GPU 10 > +#define CLK_PLL_VIDEO0 11 > +#define CLK_PLL_VIDEO0_4X 12 > +#define CLK_PLL_VIDEO1 13 > +#define CLK_PLL_VIDEO1_4X 14 > +#define CLK_PLL_VIDEO2 15 > +#define CLK_PLL_VIDEO2_4X 16 > +#define CLK_PLL_VE 17 > +#define CLK_PLL_DE 18 > +#define CLK_PLL_AUDIO_HS 19 > +#define CLK_PLL_AUDIO_1X 20 > +#define CLK_PLL_AUDIO_2X 21 > +#define CLK_PLL_AUDIO_4X 22 > + > +/* CPUX clock exported for DVFS */ > + > +#define CLK_AXI 24 > +#define CLK_CPUX_APB 25 > +#define CLK_PSI_AHB1_AHB2 26 > +#define CLK_AHB3 27 > + > +/* APB1 clock exported for PIO */ > + > +#define CLK_APB2 29 > +#define CLK_MBUS 30 > + > +/* All module clocks and bus gates are exported except DRAM */ > + > +#define CLK_DRAM 51 > + > +#define CLK_BUS_DRAM 58 > + > +#define CLK_NUMBER (CLK_BUS_HDCP + 1) > + > +#endif /* _CCU_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h > b/include/dt-bindings/clock/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..a9cc8844e3a9 > --- /dev/null > +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h > @@ -0,0 +1,110 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2020 Arm Ltd. > + */ > + > +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ > +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ > + > +#define CLK_PLL_PERIPH0 4 > + > +#define CLK_CPUX 23 > + > +#define CLK_APB1 28 > + > +#define CLK_DE 31 > +#define CLK_BUS_DE 32 > +#define CLK_DEINTERLACE 33 > +#define CLK_BUS_DEINTERLACE 34 > +#define CLK_G2D 35 > +#define CLK_BUS_G2D 36 > +#define CLK_GPU0 37 > +#define CLK_BUS_GPU 38 > +#define CLK_GPU1 39 > +#define CLK_CE 40 > +#define CLK_BUS_CE 41 > +#define CLK_VE 42 > +#define CLK_BUS_VE 43 > +#define CLK_BUS_DMA 44 > +#define CLK_BUS_HSTIMER 45 > +#define CLK_AVS 46 > +#define CLK_BUS_DBG 47 > +#define CLK_BUS_PSI 48 > +#define CLK_BUS_PWM 49 > +#define CLK_BUS_IOMMU 50 > + > +#define CLK_MBUS_DMA 52 > +#define CLK_MBUS_VE 53 > +#define CLK_MBUS_CE 54 > +#define CLK_MBUS_TS 55 > +#define CLK_MBUS_NAND 56 > +#define CLK_MBUS_G2D 57 > + > +#define CLK_NAND0 59 > +#define CLK_NAND1 60 > +#define CLK_BUS_NAND 61 > +#define CLK_MMC0 62 > +#define CLK_MMC1 63 > +#define CLK_MMC2 64 > +#define CLK_BUS_MMC0 65 > +#define CLK_BUS_MMC1 66 > +#define CLK_BUS_MMC2 67 > +#define CLK_BUS_UART0 68 > +#define CLK_BUS_UART1 69 > +#define CLK_BUS_UART2 70 > +#define CLK_BUS_UART3 71 > +#define CLK_BUS_UART4 72 > +#define CLK_BUS_UART5 73 > +#define CLK_BUS_I2C0 74 > +#define CLK_BUS_I2C1 75 > +#define CLK_BUS_I2C2 76 > +#define CLK_BUS_I2C3 77 > +#define CLK_BUS_I2C4 78 > +#define CLK_SPI0 79 > +#define CLK_SPI1 80 > +#define CLK_BUS_SPI0 81 > +#define CLK_BUS_SPI1 82 > +#define CLK_EMAC_25M 83 > +#define CLK_BUS_EMAC0 84 > +#define CLK_BUS_EMAC1 85 > +#define CLK_TS 86 > +#define CLK_BUS_TS 87 > +#define CLK_BUS_THS 88 > +#define CLK_SPDIF 89 > +#define CLK_BUS_SPDIF 90 > +#define CLK_DMIC 91 > +#define CLK_BUS_DMIC 92 > +#define CLK_AUDIO_CODEC_1X 93 > +#define CLK_AUDIO_CODEC_4X 94 > +#define CLK_BUS_AUDIO_CODEC 95 > +#define CLK_AUDIO_HUB 96 > +#define CLK_BUS_AUDIO_HUB 97 > +#define CLK_USB_OHCI0 98 > +#define CLK_USB_PHY0 99 > +#define CLK_USB_OHCI1 100 > +#define CLK_USB_PHY1 101 > +#define CLK_USB_OHCI2 102 > +#define CLK_USB_PHY2 103 > +#define CLK_USB_OHCI3 104 > +#define CLK_USB_PHY3 105 > +#define CLK_BUS_OHCI0 106 > +#define CLK_BUS_OHCI1 107 > +#define CLK_BUS_OHCI2 108 > +#define CLK_BUS_OHCI3 109 > +#define CLK_BUS_EHCI0 110 > +#define CLK_BUS_EHCI1 111 > +#define CLK_BUS_EHCI2 112 > +#define CLK_BUS_EHCI3 113 > +#define CLK_BUS_OTG 114 > +#define CLK_BUS_KEYADC 115 > +#define CLK_HDMI 116 > +#define CLK_HDMI_SLOW 117 > +#define CLK_HDMI_CEC 118 > +#define CLK_BUS_HDMI 119 > +#define CLK_BUS_TCON_TOP 120 > +#define CLK_TCON_TV0 121 > +#define CLK_BUS_TCON_TV0 122 > +#define CLK_HDCP 123 > +#define CLK_BUS_HDCP 124 > + > +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ > diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h > b/include/dt-bindings/reset/sun50i-h616-ccu.h > new file mode 100644 > index 000000000000..1c992cfbbbab > --- /dev/null > +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h > @@ -0,0 +1,67 @@ > +// SPDX-License-Identifier: (GPL-2.0+ or MIT) > +/* > + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> > + */ > + > +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ > +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ > + > +#define RST_MBUS 0 > +#define RST_BUS_DE 1 > +#define RST_BUS_DEINTERLACE 2 > +#define RST_BUS_GPU 3 > +#define RST_BUS_CE 4 > +#define RST_BUS_VE 5 > +#define RST_BUS_DMA 6 > +#define RST_BUS_HSTIMER 7 > +#define RST_BUS_DBG 8 > +#define RST_BUS_PSI 9 > +#define RST_BUS_PWM 10 > +#define RST_BUS_IOMMU 11 > +#define RST_BUS_DRAM 12 > +#define RST_BUS_NAND 13 > +#define RST_BUS_MMC0 14 > +#define RST_BUS_MMC1 15 > +#define RST_BUS_MMC2 16 > +#define RST_BUS_UART0 17 > +#define RST_BUS_UART1 18 > +#define RST_BUS_UART2 19 > +#define RST_BUS_UART3 20 > +#define RST_BUS_UART4 21 > +#define RST_BUS_UART5 22 > +#define RST_BUS_I2C0 23 > +#define RST_BUS_I2C1 24 > +#define RST_BUS_I2C2 25 > +#define RST_BUS_I2C3 26 > +#define RST_BUS_I2C4 27 > +#define RST_BUS_SPI0 28 > +#define RST_BUS_SPI1 29 > +#define RST_BUS_EMAC0 30 > +#define RST_BUS_EMAC1 31 > +#define RST_BUS_TS 32 > +#define RST_BUS_THS 33 > +#define RST_BUS_SPDIF 34 > +#define RST_BUS_DMIC 35 > +#define RST_BUS_AUDIO_CODEC 36 > +#define RST_BUS_AUDIO_HUB 37 > +#define RST_USB_PHY0 38 > +#define RST_USB_PHY1 39 > +#define RST_USB_PHY2 40 > +#define RST_USB_PHY3 41 > +#define RST_BUS_OHCI0 42 > +#define RST_BUS_OHCI1 43 > +#define RST_BUS_OHCI2 44 > +#define RST_BUS_OHCI3 45 > +#define RST_BUS_EHCI0 46 > +#define RST_BUS_EHCI1 47 > +#define RST_BUS_EHCI2 48 > +#define RST_BUS_EHCI3 49 > +#define RST_BUS_OTG 50 > +#define RST_BUS_HDMI 51 > +#define RST_BUS_HDMI_SUB 52 > +#define RST_BUS_TCON_TOP 53 > +#define RST_BUS_TCON_TV0 54 > +#define RST_BUS_HDCP 55 > +#define RST_BUS_KEYADC 56 > + > +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ > -- > 2.17.5 >
On 10/12/2020 13:31, Icenowy Zheng wrote: > 在 2020-12-02星期三的 13:54 +0000,Andre Przywara写道: >> While the clocks are fairly similar to the H6, many differ in tiny >> details, so a separate clock driver seems indicated. >> >> Derived from the H6 clock driver, and adjusted according to the >> manual. >> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com> >> --- >> drivers/clk/sunxi-ng/Kconfig | 7 +- >> drivers/clk/sunxi-ng/Makefile | 1 + >> drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 >> +++++++++++++++++++ >> drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + >> include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ >> include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ >> 6 files changed, 1376 insertions(+), 1 deletion(-) >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h >> create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h >> >> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi- >> ng/Kconfig >> index ce5f5847d5d3..cd46d8853876 100644 >> --- a/drivers/clk/sunxi-ng/Kconfig >> +++ b/drivers/clk/sunxi-ng/Kconfig >> @@ -32,8 +32,13 @@ config SUN50I_H6_CCU >> default ARM64 && ARCH_SUNXI >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> >> +config SUN50I_H616_CCU >> + bool "Support for the Allwinner H616 CCU" >> + default ARM64 && ARCH_SUNXI >> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> + >> config SUN50I_H6_R_CCU >> - bool "Support for the Allwinner H6 PRCM CCU" >> + bool "Support for the Allwinner H6 and H616 PRCM CCU" >> default ARM64 && ARCH_SUNXI >> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST >> >> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi- >> ng/Makefile >> index 3eb5cff40eac..96c324306d97 100644 >> --- a/drivers/clk/sunxi-ng/Makefile >> +++ b/drivers/clk/sunxi-ng/Makefile >> @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i- >> a64.o >> obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o >> obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o >> obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o >> +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o >> obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o >> obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o >> obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o >> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> new file mode 100644 >> index 000000000000..3fbb258f0354 >> --- /dev/null >> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c >> @@ -0,0 +1,1134 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Copyright (c) 2020 Arm Ltd. >> + * Based on the H6 CCU driver, which is: >> + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> >> + */ >> + >> +#include <linux/clk-provider.h> >> +#include <linux/io.h> >> +#include <linux/of_address.h> >> +#include <linux/platform_device.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-sun50i-h616.h" >> + >> +/* >> + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. >> However >> + * P should only be used for output frequencies lower than 288 MHz. >> + * >> + * For now we can just model it as a multiplier clock, and force P >> to /1. >> + * >> + * The M factor is present in the register's description, but not in >> the >> + * frequency formula, and it's documented as "M is only used for >> backdoor >> + * testing", so it's not modelled and then force to 0. >> + */ >> +#define SUN50I_H616_PLL_CPUX_REG 0x000 >> +static struct ccu_mult pll_cpux_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .common = { >> + .reg = 0x000, >> + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", >> + &ccu_mult_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K >> */ >> +#define SUN50I_H616_PLL_DDR0_REG 0x010 >> +static struct ccu_nkmp pll_ddr0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x010, >> + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_DDR1_REG 0x018 >> +static struct ccu_nkmp pll_ddr1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x018, >> + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 >> +static struct ccu_nkmp pll_periph0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .fixed_post_div = 4, > > Isn't it 2 here? > > The user manual says: > > ``` > PLL_PERI0(2X) = 24 MHz*N/M0/M1 > PLL_PERI0(1X) = 24 MHz*N/M0/M1/2 Ouch, you are right, good catch! I ripped out PLL_PERI0(4X) last minute, but missed that divider. Thanks! Andre > ``` > > + .common = { >> + .reg = 0x020, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 >> +static struct ccu_nkmp pll_periph1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .fixed_post_div = 4, >> + .common = { >> + .reg = 0x028, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_GPU_REG 0x030 >> +static struct ccu_nkmp pll_gpu_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x030, >> + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* >> + * For Video PLLs, the output divider is described as "used for >> testing" >> + * in the user manual. So it's not modelled and forced to 0. >> + */ >> +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 >> +static struct ccu_nm pll_video0_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x040, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 >> +static struct ccu_nm pll_video1_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x048, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 >> +static struct ccu_nm pll_video2_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .fixed_post_div = 4, >> + .min_rate = 288000000, >> + .max_rate = 2400000000UL, >> + .common = { >> + .reg = 0x050, >> + .features = CCU_FEATURE_FIXED_POSTDIV, >> + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_VE_REG 0x058 >> +static struct ccu_nkmp pll_ve_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x058, >> + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +#define SUN50I_H616_PLL_DE_REG 0x060 >> +static struct ccu_nkmp pll_de_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ >> + .common = { >> + .reg = 0x060, >> + .hw.init = CLK_HW_INIT("pll-de", "osc24M", >> + &ccu_nkmp_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +/* >> + * TODO: Determine SDM settings for the audio PLL. The manual >> suggests >> + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, >> pattern=0xe000c49b >> + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, >> OUTPUT_DIV=2, >> + * pattern=0xe001288c for 22.5792 MHz. >> + * This clashes with our fixed PLL_POST_DIV_P. >> + */ >> +#define SUN50I_H616_PLL_AUDIO_REG 0x078 >> +static struct ccu_nm pll_audio_hs_clk = { >> + .enable = BIT(31), >> + .lock = BIT(28), >> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), >> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ >> + .common = { >> + .reg = 0x078, >> + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", >> + &ccu_nm_ops, >> + CLK_SET_RATE_UNGATE), >> + }, >> +}; >> + >> +static const char * const cpux_parents[] = { "osc24M", "osc32k", >> + "iosc", "pll-cpux", "pll- >> periph0" }; >> +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, >> + 0x500, 24, 3, CLK_SET_RATE_PARENT | >> CLK_IS_CRITICAL); >> +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); >> +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, >> 0); >> + >> +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", >> "osc32k", >> + "iosc", "pll- >> periph0" }; >> +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", >> + psi_ahb1_ahb2_parents, >> + 0x510, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", >> "osc32k", >> + "psi-ahb1-ahb2", >> + "pll-periph0" }; >> +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", >> ahb3_apb1_apb2_parents, 0x51c, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", >> ahb3_apb1_apb2_parents, 0x520, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", >> ahb3_apb1_apb2_parents, 0x524, >> + 0, 2, /* M */ >> + 8, 2, /* P */ >> + 24, 2, /* mux */ >> + 0); >> + >> +static const char * const mbus_parents[] = { "osc24M", "pll-periph0- >> 2x", >> + "pll-ddr0", "pll-ddr1" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, >> 0x540, >> + 0, 3, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_IS_CRITICAL); >> + >> +static const char * const de_parents[] = { "pll-de", "pll-periph0- >> 2x" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", >> + 0x60c, BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", >> + de_parents, >> + 0x620, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi- >> ahb1-ahb2", >> + 0x62c, BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, >> + 0, 4, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", >> + 0x63c, BIT(0), 0); >> + >> +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, >> 0x670, >> + 0, 2, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", >> 0x674, >> + 0, 3, /* M */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", >> + 0x67c, BIT(0), 0); >> + >> +static const char * const ce_parents[] = { "osc24M", "pll-periph0- >> 2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 1, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", >> + 0x68c, BIT(0), 0); >> + >> +static const char * const ve_parents[] = { "pll-ve" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, >> + 0, 3, /* M */ >> + 24, 1, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", >> + 0x69c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", >> + 0x70c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1- >> ahb2", >> + 0x73c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); >> + >> +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", >> + 0x78c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", >> + 0x79c, BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), >> 0); >> + >> +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, >> BIT(0), 0); >> + >> +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" >> }; >> +static struct ccu_div dram_clk = { >> + .div = _SUNXI_CCU_DIV(0, 2), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0x800, >> + .hw.init = CLK_HW_INIT_PARENTS("dram", >> + dram_parents, >> + &ccu_div_ops, >> + CLK_IS_CRITICAL), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", >> + 0x804, BIT(0), 0); >> +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", >> + 0x804, BIT(1), 0); >> +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", >> + 0x804, BIT(2), 0); >> +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", >> + 0x804, BIT(3), 0); >> +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", >> + 0x804, BIT(5), 0); >> +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", >> + 0x804, BIT(10), 0); >> + >> +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", >> + 0x80c, BIT(0), CLK_IS_CRITICAL); >> + >> +static const char * const nand_spi_parents[] = { "osc24M", "pll- >> periph0", >> + "pll-periph1", "pll- >> periph0-2x", >> + "pll-periph1-2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", >> nand_spi_parents, 0x810, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", >> nand_spi_parents, 0x814, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, >> BIT(0), 0); >> + >> +static const char * const mmc_parents[] = { "osc24M", "pll-periph0- >> 2x", >> + "pll-periph1-2x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", >> mmc_parents, 0x830, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div >> */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", >> mmc_parents, 0x834, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div >> */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", >> mmc_parents, 0x838, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 2, /* post-div >> */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, >> BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, >> BIT(2), 0); >> + >> +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, >> BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, >> BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, >> BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, >> BIT(4), 0); >> +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, >> BIT(5), 0); >> + >> +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, >> BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, >> BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, >> BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, >> BIT(4), 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", >> nand_spi_parents, 0x940, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", >> nand_spi_parents, 0x944, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 3, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, >> BIT(1), 0); >> + >> +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, >> + BIT(31) | BIT(30), 0); >> + >> +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, >> BIT(1), 0); >> + >> +static const char * const ts_parents[] = { "osc24M", "pll-periph0" >> }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, >> + 0, 4, /* M */ >> + 8, 2, /* N */ >> + 24, 1, /* mux */ >> + BIT(31),/* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), >> 0); >> + >> +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), >> 0); >> + >> +static const char * const audio_parents[] = { "pll-audio-1x", "pll- >> audio-2x", >> + "pll-audio-4x", "pll- >> audio-hs" }; >> +static struct ccu_div spdif_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >> CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa20, >> + .hw.init = CLK_HW_INIT_PARENTS("spdif", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, >> BIT(0), 0); >> + >> +static struct ccu_div dmic_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >> CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa40, >> + .hw.init = CLK_HW_INIT_PARENTS("dmic", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, >> BIT(0), 0); >> + >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec- >> 1x", >> + audio_parents, 0xa50, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec- >> 4x", >> + audio_parents, 0xa54, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", >> "apb1", 0xa5c, >> + BIT(0), 0); >> + >> +static struct ccu_div audio_hub_clk = { >> + .enable = BIT(31), >> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, >> CLK_DIVIDER_POWER_OF_TWO), >> + .mux = _SUNXI_CCU_MUX(24, 2), >> + .common = { >> + .reg = 0xa60, >> + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", >> + audio_parents, >> + &ccu_div_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", >> 0xa6c, BIT(0), 0); >> + >> +/* >> + * There are OHCI 12M clock source selection bits for 2 USB 2.0 >> ports. >> + * We will force them to 0 (12M divided from 48M). >> + */ >> +#define SUN50I_H616_USB0_CLK_REG 0xa70 >> +#define SUN50I_H616_USB1_CLK_REG 0xa74 >> +#define SUN50I_H616_USB2_CLK_REG 0xa78 >> +#define SUN50I_H616_USB3_CLK_REG 0xa7c >> + >> +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, >> BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, >> BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, >> BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, >> BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, >> BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, >> BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, >> BIT(31), 0); >> +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, >> BIT(29), 0); >> + >> +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, >> BIT(0), 0); >> +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, >> BIT(1), 0); >> +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, >> BIT(2), 0); >> +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, >> BIT(3), 0); >> +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, >> BIT(4), 0); >> +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, >> BIT(5), 0); >> +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, >> BIT(6), 0); >> +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, >> BIT(7), 0); >> +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), >> 0); >> + >> +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, >> BIT(0), 0); >> + >> +static struct clk_fixed_factor pll_periph0_4x_clk; >> + >> +static const char * const hdmi_parents[] = { "pll-video0", "pll- >> video0-4x", >> + "pll-video2", "pll-video2- >> 4x" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, >> 0xb00, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, >> BIT(31), 0); >> + >> +static const char * const hdmi_cec_parents[] = { "osc32k", "pll- >> periph0-2x" }; >> +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { >> + { .index = 1, .div = 36621 }, >> +}; >> + >> +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 >> +static struct ccu_mux hdmi_cec_clk = { >> + .enable = BIT(31), >> + >> + .mux = { >> + .shift = 24, >> + .width = 2, >> + >> + .fixed_predivs = hdmi_cec_predivs, >> + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), >> + }, >> + >> + .common = { >> + .reg = 0xb10, >> + .features = CCU_FEATURE_VARIABLE_PREDIV, >> + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", >> + hdmi_cec_parents, >> + &ccu_mux_ops, >> + 0), >> + }, >> +}; >> + >> +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, >> BIT(0), 0); >> + >> +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", >> + 0xb5c, BIT(0), 0); >> + >> +static const char * const tcon_tv0_parents[] = { "pll-video0", >> + "pll-video0-4x", >> + "pll-video1", >> + "pll-video1-4x" }; >> +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", >> + tcon_tv0_parents, 0xb80, >> + 0, 4, /* M */ >> + 8, 2, /* P */ >> + 24, 3, /* mux */ >> + BIT(31), /* gate */ >> + CLK_SET_RATE_PARENT); >> + >> +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", >> + 0xb9c, BIT(0), 0); >> + >> +static const char * const hdcp_parents[] = { "pll-periph0", "pll- >> periph1" }; >> +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, >> 0xc40, >> + 0, 4, /* M */ >> + 24, 2, /* mux */ >> + BIT(31), /* gate */ >> + 0); >> + >> +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, >> BIT(0), 0); >> + >> +/* Fixed factor clocks */ >> +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, >> 0); >> + >> +static const struct clk_hw *clk_parent_pll_audio[] = { >> + &pll_audio_hs_clk.common.hw >> +}; >> + >> +/* >> + * The divider of pll-audio is fixed to 24 for now, so 24576000 and >> 22579200 >> + * rates can be set exactly in conjunction with sigma-delta >> modulation. >> + */ >> +static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", >> + clk_parent_pll_audio, >> + 96, 1, CLK_SET_RATE_PARENT); >> +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", >> + clk_parent_pll_audio, >> + 48, 1, CLK_SET_RATE_PARENT); >> +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", >> + clk_parent_pll_audio, >> + 24, 1, CLK_SET_RATE_PARENT); >> + >> +static const struct clk_hw *pll_periph0_parents[] = { >> + &pll_periph0_clk.common.hw >> +}; >> +static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x", >> + pll_periph0_parents, >> + 1, 4, 0); >> +static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x", >> + pll_periph0_parents, >> + 1, 2, 0); >> + >> +static const struct clk_hw *pll_periph1_parents[] = { >> + &pll_periph1_clk.common.hw >> +}; >> +static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x", >> + pll_periph1_parents, >> + 1, 4, 0); >> +static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x", >> + pll_periph1_parents, >> + 1, 2, 0); >> + >> +static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x", >> + &pll_video0_clk.common.hw, >> + 1, 4, CLK_SET_RATE_PARENT); >> +static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x", >> + &pll_video1_clk.common.hw, >> + 1, 4, CLK_SET_RATE_PARENT); >> +static CLK_FIXED_FACTOR_HW(pll_video2_4x_clk, "pll-video2-4x", >> + &pll_video2_clk.common.hw, >> + 1, 4, CLK_SET_RATE_PARENT); >> + >> +static struct ccu_common *sun50i_h616_ccu_clks[] = { >> + &pll_cpux_clk.common, >> + &pll_ddr0_clk.common, >> + &pll_ddr1_clk.common, >> + &pll_periph0_clk.common, >> + &pll_periph1_clk.common, >> + &pll_gpu_clk.common, >> + &pll_video0_clk.common, >> + &pll_video1_clk.common, >> + &pll_video2_clk.common, >> + &pll_ve_clk.common, >> + &pll_de_clk.common, >> + &pll_audio_hs_clk.common, >> + &cpux_clk.common, >> + &axi_clk.common, >> + &cpux_apb_clk.common, >> + &psi_ahb1_ahb2_clk.common, >> + &ahb3_clk.common, >> + &apb1_clk.common, >> + &apb2_clk.common, >> + &mbus_clk.common, >> + &de_clk.common, >> + &bus_de_clk.common, >> + &deinterlace_clk.common, >> + &bus_deinterlace_clk.common, >> + &g2d_clk.common, >> + &bus_g2d_clk.common, >> + &gpu0_clk.common, >> + &bus_gpu_clk.common, >> + &gpu1_clk.common, >> + &ce_clk.common, >> + &bus_ce_clk.common, >> + &ve_clk.common, >> + &bus_ve_clk.common, >> + &bus_dma_clk.common, >> + &bus_hstimer_clk.common, >> + &avs_clk.common, >> + &bus_dbg_clk.common, >> + &bus_psi_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_ts_clk.common, >> + &mbus_nand_clk.common, >> + &mbus_g2d_clk.common, >> + &bus_dram_clk.common, >> + &nand0_clk.common, >> + &nand1_clk.common, >> + &bus_nand_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_uart4_clk.common, >> + &bus_uart5_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, >> + &bus_spi0_clk.common, >> + &bus_spi1_clk.common, >> + &emac_25m_clk.common, >> + &bus_emac0_clk.common, >> + &bus_emac1_clk.common, >> + &ts_clk.common, >> + &bus_ts_clk.common, >> + &bus_ths_clk.common, >> + &spdif_clk.common, >> + &bus_spdif_clk.common, >> + &dmic_clk.common, >> + &bus_dmic_clk.common, >> + &audio_codec_1x_clk.common, >> + &audio_codec_4x_clk.common, >> + &bus_audio_codec_clk.common, >> + &audio_hub_clk.common, >> + &bus_audio_hub_clk.common, >> + &usb_ohci0_clk.common, >> + &usb_phy0_clk.common, >> + &usb_ohci1_clk.common, >> + &usb_phy1_clk.common, >> + &usb_ohci2_clk.common, >> + &usb_phy2_clk.common, >> + &usb_ohci3_clk.common, >> + &usb_phy3_clk.common, >> + &bus_ohci0_clk.common, >> + &bus_ohci1_clk.common, >> + &bus_ohci2_clk.common, >> + &bus_ohci3_clk.common, >> + &bus_ehci0_clk.common, >> + &bus_ehci1_clk.common, >> + &bus_ehci2_clk.common, >> + &bus_ehci3_clk.common, >> + &bus_otg_clk.common, >> + &bus_keyadc_clk.common, >> + &hdmi_clk.common, >> + &hdmi_slow_clk.common, >> + &hdmi_cec_clk.common, >> + &bus_hdmi_clk.common, >> + &bus_tcon_top_clk.common, >> + &tcon_tv0_clk.common, >> + &bus_tcon_tv0_clk.common, >> + &hdcp_clk.common, >> + &bus_hdcp_clk.common, >> +}; >> + >> +static struct clk_hw_onecell_data sun50i_h616_hw_clks = { >> + .hws = { >> + [CLK_OSC12M] = &osc12M_clk.hw, >> + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, >> + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, >> + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, >> + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, >> + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, >> + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, >> + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, >> + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, >> + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, >> + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, >> + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, >> + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, >> + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, >> + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, >> + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, >> + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, >> + [CLK_PLL_VE] = &pll_ve_clk.common.hw, >> + [CLK_PLL_DE] = &pll_de_clk.common.hw, >> + [CLK_PLL_AUDIO_HS] = >> &pll_audio_hs_clk.common.hw, >> + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.hw, >> + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, >> + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, >> + [CLK_CPUX] = &cpux_clk.common.hw, >> + [CLK_AXI] = &axi_clk.common.hw, >> + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, >> + [CLK_PSI_AHB1_AHB2] = >> &psi_ahb1_ahb2_clk.common.hw, >> + [CLK_AHB3] = &ahb3_clk.common.hw, >> + [CLK_APB1] = &apb1_clk.common.hw, >> + [CLK_APB2] = &apb2_clk.common.hw, >> + [CLK_MBUS] = &mbus_clk.common.hw, >> + [CLK_DE] = &de_clk.common.hw, >> + [CLK_BUS_DE] = &bus_de_clk.common.hw, >> + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, >> + [CLK_BUS_DEINTERLACE] = >> &bus_deinterlace_clk.common.hw, >> + [CLK_G2D] = &g2d_clk.common.hw, >> + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, >> + [CLK_GPU0] = &gpu0_clk.common.hw, >> + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, >> + [CLK_GPU1] = &gpu1_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_BUS_DMA] = &bus_dma_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_PSI] = &bus_psi_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_TS] = &mbus_ts_clk.common.hw, >> + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, >> + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, >> + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, >> + [CLK_NAND0] = &nand0_clk.common.hw, >> + [CLK_NAND1] = &nand1_clk.common.hw, >> + [CLK_BUS_NAND] = &bus_nand_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_UART4] = &bus_uart4_clk.common.hw, >> + [CLK_BUS_UART5] = &bus_uart5_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_BUS_SPI0] = &bus_spi0_clk.common.hw, >> + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, >> + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, >> + [CLK_BUS_EMAC0] = &bus_emac0_clk.common.hw, >> + [CLK_BUS_EMAC1] = &bus_emac1_clk.common.hw, >> + [CLK_TS] = &ts_clk.common.hw, >> + [CLK_BUS_TS] = &bus_ts_clk.common.hw, >> + [CLK_BUS_THS] = &bus_ths_clk.common.hw, >> + [CLK_SPDIF] = &spdif_clk.common.hw, >> + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, >> + [CLK_DMIC] = &dmic_clk.common.hw, >> + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, >> + [CLK_AUDIO_CODEC_1X] = >> &audio_codec_1x_clk.common.hw, >> + [CLK_AUDIO_CODEC_4X] = >> &audio_codec_4x_clk.common.hw, >> + [CLK_BUS_AUDIO_CODEC] = >> &bus_audio_codec_clk.common.hw, >> + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, >> + [CLK_BUS_AUDIO_HUB] = >> &bus_audio_hub_clk.common.hw, >> + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, >> + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, >> + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, >> + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, >> + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, >> + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, >> + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, >> + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, >> + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, >> + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, >> + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, >> + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, >> + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, >> + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, >> + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, >> + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, >> + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, >> + [CLK_BUS_KEYADC] = &bus_keyadc_clk.common.hw, >> + [CLK_HDMI] = &hdmi_clk.common.hw, >> + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, >> + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, >> + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, >> + [CLK_BUS_TCON_TOP] = >> &bus_tcon_top_clk.common.hw, >> + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, >> + [CLK_BUS_TCON_TV0] = >> &bus_tcon_tv0_clk.common.hw, >> + [CLK_HDCP] = &hdcp_clk.common.hw, >> + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, >> + }, >> + .num = CLK_NUMBER, >> +}; >> + >> +static struct ccu_reset_map sun50i_h616_ccu_resets[] = { >> + [RST_MBUS] = { 0x540, BIT(30) }, >> + >> + [RST_BUS_DE] = { 0x60c, BIT(16) }, >> + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, >> + [RST_BUS_GPU] = { 0x67c, BIT(16) }, >> + [RST_BUS_CE] = { 0x68c, BIT(16) }, >> + [RST_BUS_VE] = { 0x69c, BIT(16) }, >> + [RST_BUS_DMA] = { 0x70c, BIT(16) }, >> + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, >> + [RST_BUS_DBG] = { 0x78c, BIT(16) }, >> + [RST_BUS_PSI] = { 0x79c, BIT(16) }, >> + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, >> + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, >> + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, >> + [RST_BUS_NAND] = { 0x82c, 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_UART4] = { 0x90c, BIT(20) }, >> + [RST_BUS_UART5] = { 0x90c, BIT(21) }, >> + [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_EMAC0] = { 0x97c, BIT(16) }, >> + [RST_BUS_EMAC1] = { 0x97c, BIT(17) }, >> + [RST_BUS_TS] = { 0x9bc, BIT(16) }, >> + [RST_BUS_THS] = { 0x9fc, BIT(16) }, >> + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, >> + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, >> + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, >> + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, >> + >> + [RST_USB_PHY0] = { 0xa70, BIT(30) }, >> + [RST_USB_PHY1] = { 0xa74, BIT(30) }, >> + [RST_USB_PHY2] = { 0xa78, BIT(30) }, >> + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, >> + >> + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, >> + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, >> + [RST_BUS_OHCI2] = { 0xa8c, BIT(18) }, >> + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, >> + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, >> + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, >> + [RST_BUS_EHCI2] = { 0xa8c, BIT(22) }, >> + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, >> + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, >> + [RST_BUS_KEYADC] = { 0xa9c, BIT(16) }, >> + >> + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, >> + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, >> + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, >> + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, >> + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, >> +}; >> + >> +static const struct sunxi_ccu_desc sun50i_h616_ccu_desc = { >> + .ccu_clks = sun50i_h616_ccu_clks, >> + .num_ccu_clks = ARRAY_SIZE(sun50i_h616_ccu_clks), >> + >> + .hw_clks = &sun50i_h616_hw_clks, >> + >> + .resets = sun50i_h616_ccu_resets, >> + .num_resets = ARRAY_SIZE(sun50i_h616_ccu_resets), >> +}; >> + >> +static const u32 pll_regs[] = { >> + SUN50I_H616_PLL_CPUX_REG, >> + SUN50I_H616_PLL_DDR0_REG, >> + SUN50I_H616_PLL_DDR1_REG, >> + SUN50I_H616_PLL_PERIPH0_REG, >> + SUN50I_H616_PLL_PERIPH1_REG, >> + SUN50I_H616_PLL_GPU_REG, >> + SUN50I_H616_PLL_VIDEO0_REG, >> + SUN50I_H616_PLL_VIDEO1_REG, >> + SUN50I_H616_PLL_VIDEO2_REG, >> + SUN50I_H616_PLL_VE_REG, >> + SUN50I_H616_PLL_DE_REG, >> + SUN50I_H616_PLL_AUDIO_REG, >> +}; >> + >> +static const u32 pll_video_regs[] = { >> + SUN50I_H616_PLL_VIDEO0_REG, >> + SUN50I_H616_PLL_VIDEO1_REG, >> + SUN50I_H616_PLL_VIDEO2_REG, >> +}; >> + >> +static const u32 usb2_clk_regs[] = { >> + SUN50I_H616_USB0_CLK_REG, >> + SUN50I_H616_USB1_CLK_REG, >> + SUN50I_H616_USB2_CLK_REG, >> + SUN50I_H616_USB3_CLK_REG, >> +}; >> + >> +static int sun50i_h616_ccu_probe(struct platform_device *pdev) >> +{ >> + struct resource *res; >> + void __iomem *reg; >> + u32 val; >> + int i; >> + >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + reg = devm_ioremap_resource(&pdev->dev, res); >> + if (IS_ERR(reg)) >> + return PTR_ERR(reg); >> + >> + /* Enable the lock bits on all PLLs */ >> + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { >> + val = readl(reg + pll_regs[i]); >> + val |= BIT(29); >> + writel(val, reg + pll_regs[i]); >> + } >> + >> + /* >> + * Force the output divider of video PLLs to 0. >> + * >> + * See the comment before pll-video0 definition for the reason. >> + */ >> + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { >> + val = readl(reg + pll_video_regs[i]); >> + val &= ~BIT(0); >> + writel(val, reg + pll_video_regs[i]); >> + } >> + >> + /* >> + * Force OHCI 12M clock sources to 00 (12MHz divided from >> 48MHz) >> + * >> + * This clock mux is still mysterious, and the code just >> enforces >> + * it to have a valid clock parent. >> + */ >> + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { >> + val = readl(reg + usb2_clk_regs[i]); >> + val &= ~GENMASK(25, 24); >> + writel (val, reg + usb2_clk_regs[i]); >> + } >> + >> + /* >> + * Force the post-divider of pll-audio to 12 and the output >> divider >> + * of it to 2, so 24576000 and 22579200 rates can be set >> exactly. >> + */ >> + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); >> + val &= ~(GENMASK(21, 16) | BIT(0)); >> + writel(val | (11 << 16) | BIT(0), reg + >> SUN50I_H616_PLL_AUDIO_REG); >> + >> + /* >> + * First clock parent (osc32K) is unusable for CEC. But since >> there >> + * is no good way to force parent switch (both run with same >> frequency), >> + * just set second clock parent here. >> + */ >> + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); >> + val |= BIT(24); >> + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); >> + >> + return sunxi_ccu_probe(pdev->dev.of_node, reg, >> &sun50i_h616_ccu_desc); >> +} >> + >> +static const struct of_device_id sun50i_h616_ccu_ids[] = { >> + { .compatible = "allwinner,sun50i-h616-ccu", >> + .data = &sun50i_h616_ccu_desc }, >> + { } >> +}; >> + >> +static struct platform_driver sun50i_h616_ccu_driver = { >> + .probe = sun50i_h616_ccu_probe, >> + .driver = { >> + .name = "sun50i-h616-ccu", >> + .of_match_table = sun50i_h616_ccu_ids, >> + }, >> +}; >> +builtin_platform_driver(sun50i_h616_ccu_driver); >> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> new file mode 100644 >> index 000000000000..da8f0b1206f9 >> --- /dev/null >> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h >> @@ -0,0 +1,58 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright 2020 Arm Ltd. >> + */ >> + >> +#ifndef _CCU_SUN50I_H616_H_ >> +#define _CCU_SUN50I_H616_H_ >> + >> +#include <dt-bindings/clock/sun50i-h616-ccu.h> >> +#include <dt-bindings/reset/sun50i-h616-ccu.h> >> + >> +#define CLK_OSC12M 0 >> +#define CLK_PLL_CPUX 1 >> +#define CLK_PLL_DDR0 2 >> +#define CLK_PLL_DDR1 3 >> + >> +/* PLL_PERIPH0 exported for PRCM */ >> + >> +#define CLK_PLL_PERIPH0_2X 5 >> +#define CLK_PLL_PERIPH0_4X 6 >> +#define CLK_PLL_PERIPH1 7 >> +#define CLK_PLL_PERIPH1_2X 8 >> +#define CLK_PLL_PERIPH1_4X 9 >> +#define CLK_PLL_GPU 10 >> +#define CLK_PLL_VIDEO0 11 >> +#define CLK_PLL_VIDEO0_4X 12 >> +#define CLK_PLL_VIDEO1 13 >> +#define CLK_PLL_VIDEO1_4X 14 >> +#define CLK_PLL_VIDEO2 15 >> +#define CLK_PLL_VIDEO2_4X 16 >> +#define CLK_PLL_VE 17 >> +#define CLK_PLL_DE 18 >> +#define CLK_PLL_AUDIO_HS 19 >> +#define CLK_PLL_AUDIO_1X 20 >> +#define CLK_PLL_AUDIO_2X 21 >> +#define CLK_PLL_AUDIO_4X 22 >> + >> +/* CPUX clock exported for DVFS */ >> + >> +#define CLK_AXI 24 >> +#define CLK_CPUX_APB 25 >> +#define CLK_PSI_AHB1_AHB2 26 >> +#define CLK_AHB3 27 >> + >> +/* APB1 clock exported for PIO */ >> + >> +#define CLK_APB2 29 >> +#define CLK_MBUS 30 >> + >> +/* All module clocks and bus gates are exported except DRAM */ >> + >> +#define CLK_DRAM 51 >> + >> +#define CLK_BUS_DRAM 58 >> + >> +#define CLK_NUMBER (CLK_BUS_HDCP + 1) >> + >> +#endif /* _CCU_SUN50I_H616_H_ */ >> diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h >> b/include/dt-bindings/clock/sun50i-h616-ccu.h >> new file mode 100644 >> index 000000000000..a9cc8844e3a9 >> --- /dev/null >> +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h >> @@ -0,0 +1,110 @@ >> +// SPDX-License-Identifier: (GPL-2.0+ or MIT) >> +/* >> + * Copyright (C) 2020 Arm Ltd. >> + */ >> + >> +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ >> +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ >> + >> +#define CLK_PLL_PERIPH0 4 >> + >> +#define CLK_CPUX 23 >> + >> +#define CLK_APB1 28 >> + >> +#define CLK_DE 31 >> +#define CLK_BUS_DE 32 >> +#define CLK_DEINTERLACE 33 >> +#define CLK_BUS_DEINTERLACE 34 >> +#define CLK_G2D 35 >> +#define CLK_BUS_G2D 36 >> +#define CLK_GPU0 37 >> +#define CLK_BUS_GPU 38 >> +#define CLK_GPU1 39 >> +#define CLK_CE 40 >> +#define CLK_BUS_CE 41 >> +#define CLK_VE 42 >> +#define CLK_BUS_VE 43 >> +#define CLK_BUS_DMA 44 >> +#define CLK_BUS_HSTIMER 45 >> +#define CLK_AVS 46 >> +#define CLK_BUS_DBG 47 >> +#define CLK_BUS_PSI 48 >> +#define CLK_BUS_PWM 49 >> +#define CLK_BUS_IOMMU 50 >> + >> +#define CLK_MBUS_DMA 52 >> +#define CLK_MBUS_VE 53 >> +#define CLK_MBUS_CE 54 >> +#define CLK_MBUS_TS 55 >> +#define CLK_MBUS_NAND 56 >> +#define CLK_MBUS_G2D 57 >> + >> +#define CLK_NAND0 59 >> +#define CLK_NAND1 60 >> +#define CLK_BUS_NAND 61 >> +#define CLK_MMC0 62 >> +#define CLK_MMC1 63 >> +#define CLK_MMC2 64 >> +#define CLK_BUS_MMC0 65 >> +#define CLK_BUS_MMC1 66 >> +#define CLK_BUS_MMC2 67 >> +#define CLK_BUS_UART0 68 >> +#define CLK_BUS_UART1 69 >> +#define CLK_BUS_UART2 70 >> +#define CLK_BUS_UART3 71 >> +#define CLK_BUS_UART4 72 >> +#define CLK_BUS_UART5 73 >> +#define CLK_BUS_I2C0 74 >> +#define CLK_BUS_I2C1 75 >> +#define CLK_BUS_I2C2 76 >> +#define CLK_BUS_I2C3 77 >> +#define CLK_BUS_I2C4 78 >> +#define CLK_SPI0 79 >> +#define CLK_SPI1 80 >> +#define CLK_BUS_SPI0 81 >> +#define CLK_BUS_SPI1 82 >> +#define CLK_EMAC_25M 83 >> +#define CLK_BUS_EMAC0 84 >> +#define CLK_BUS_EMAC1 85 >> +#define CLK_TS 86 >> +#define CLK_BUS_TS 87 >> +#define CLK_BUS_THS 88 >> +#define CLK_SPDIF 89 >> +#define CLK_BUS_SPDIF 90 >> +#define CLK_DMIC 91 >> +#define CLK_BUS_DMIC 92 >> +#define CLK_AUDIO_CODEC_1X 93 >> +#define CLK_AUDIO_CODEC_4X 94 >> +#define CLK_BUS_AUDIO_CODEC 95 >> +#define CLK_AUDIO_HUB 96 >> +#define CLK_BUS_AUDIO_HUB 97 >> +#define CLK_USB_OHCI0 98 >> +#define CLK_USB_PHY0 99 >> +#define CLK_USB_OHCI1 100 >> +#define CLK_USB_PHY1 101 >> +#define CLK_USB_OHCI2 102 >> +#define CLK_USB_PHY2 103 >> +#define CLK_USB_OHCI3 104 >> +#define CLK_USB_PHY3 105 >> +#define CLK_BUS_OHCI0 106 >> +#define CLK_BUS_OHCI1 107 >> +#define CLK_BUS_OHCI2 108 >> +#define CLK_BUS_OHCI3 109 >> +#define CLK_BUS_EHCI0 110 >> +#define CLK_BUS_EHCI1 111 >> +#define CLK_BUS_EHCI2 112 >> +#define CLK_BUS_EHCI3 113 >> +#define CLK_BUS_OTG 114 >> +#define CLK_BUS_KEYADC 115 >> +#define CLK_HDMI 116 >> +#define CLK_HDMI_SLOW 117 >> +#define CLK_HDMI_CEC 118 >> +#define CLK_BUS_HDMI 119 >> +#define CLK_BUS_TCON_TOP 120 >> +#define CLK_TCON_TV0 121 >> +#define CLK_BUS_TCON_TV0 122 >> +#define CLK_HDCP 123 >> +#define CLK_BUS_HDCP 124 >> + >> +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ >> diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h >> b/include/dt-bindings/reset/sun50i-h616-ccu.h >> new file mode 100644 >> index 000000000000..1c992cfbbbab >> --- /dev/null >> +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h >> @@ -0,0 +1,67 @@ >> +// SPDX-License-Identifier: (GPL-2.0+ or MIT) >> +/* >> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> >> + */ >> + >> +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ >> +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ >> + >> +#define RST_MBUS 0 >> +#define RST_BUS_DE 1 >> +#define RST_BUS_DEINTERLACE 2 >> +#define RST_BUS_GPU 3 >> +#define RST_BUS_CE 4 >> +#define RST_BUS_VE 5 >> +#define RST_BUS_DMA 6 >> +#define RST_BUS_HSTIMER 7 >> +#define RST_BUS_DBG 8 >> +#define RST_BUS_PSI 9 >> +#define RST_BUS_PWM 10 >> +#define RST_BUS_IOMMU 11 >> +#define RST_BUS_DRAM 12 >> +#define RST_BUS_NAND 13 >> +#define RST_BUS_MMC0 14 >> +#define RST_BUS_MMC1 15 >> +#define RST_BUS_MMC2 16 >> +#define RST_BUS_UART0 17 >> +#define RST_BUS_UART1 18 >> +#define RST_BUS_UART2 19 >> +#define RST_BUS_UART3 20 >> +#define RST_BUS_UART4 21 >> +#define RST_BUS_UART5 22 >> +#define RST_BUS_I2C0 23 >> +#define RST_BUS_I2C1 24 >> +#define RST_BUS_I2C2 25 >> +#define RST_BUS_I2C3 26 >> +#define RST_BUS_I2C4 27 >> +#define RST_BUS_SPI0 28 >> +#define RST_BUS_SPI1 29 >> +#define RST_BUS_EMAC0 30 >> +#define RST_BUS_EMAC1 31 >> +#define RST_BUS_TS 32 >> +#define RST_BUS_THS 33 >> +#define RST_BUS_SPDIF 34 >> +#define RST_BUS_DMIC 35 >> +#define RST_BUS_AUDIO_CODEC 36 >> +#define RST_BUS_AUDIO_HUB 37 >> +#define RST_USB_PHY0 38 >> +#define RST_USB_PHY1 39 >> +#define RST_USB_PHY2 40 >> +#define RST_USB_PHY3 41 >> +#define RST_BUS_OHCI0 42 >> +#define RST_BUS_OHCI1 43 >> +#define RST_BUS_OHCI2 44 >> +#define RST_BUS_OHCI3 45 >> +#define RST_BUS_EHCI0 46 >> +#define RST_BUS_EHCI1 47 >> +#define RST_BUS_EHCI2 48 >> +#define RST_BUS_EHCI3 49 >> +#define RST_BUS_OTG 50 >> +#define RST_BUS_HDMI 51 >> +#define RST_BUS_HDMI_SUB 52 >> +#define RST_BUS_TCON_TOP 53 >> +#define RST_BUS_TCON_TV0 54 >> +#define RST_BUS_HDCP 55 >> +#define RST_BUS_KEYADC 56 >> + >> +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */ >> -- >> 2.17.5 >>
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index ce5f5847d5d3..cd46d8853876 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -32,8 +32,13 @@ config SUN50I_H6_CCU default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST +config SUN50I_H616_CCU + bool "Support for the Allwinner H616 CCU" + default ARM64 && ARCH_SUNXI + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + config SUN50I_H6_R_CCU - bool "Support for the Allwinner H6 PRCM CCU" + bool "Support for the Allwinner H6 and H616 PRCM CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 3eb5cff40eac..96c324306d97 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o +obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c new file mode 100644 index 000000000000..3fbb258f0354 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c @@ -0,0 +1,1134 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Arm Ltd. + * Based on the H6 CCU driver, which is: + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io> + */ + +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/platform_device.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-sun50i-h616.h" + +/* + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However + * P should only be used for output frequencies lower than 288 MHz. + * + * For now we can just model it as a multiplier clock, and force P to /1. + * + * The M factor is present in the register's description, but not in the + * frequency formula, and it's documented as "M is only used for backdoor + * testing", so it's not modelled and then force to 0. + */ +#define SUN50I_H616_PLL_CPUX_REG 0x000 +static struct ccu_mult pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", "osc24M", + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ +#define SUN50I_H616_PLL_DDR0_REG 0x010 +static struct ccu_nkmp pll_ddr0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x010, + .hw.init = CLK_HW_INIT("pll-ddr0", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_DDR1_REG 0x018 +static struct ccu_nkmp pll_ddr1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x018, + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_PERIPH0_REG 0x020 +static struct ccu_nkmp pll_periph0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x020, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_PERIPH1_REG 0x028 +static struct ccu_nkmp pll_periph1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x028, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_GPU_REG 0x030 +static struct ccu_nkmp pll_gpu_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x030, + .hw.init = CLK_HW_INIT("pll-gpu", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * For Video PLLs, the output divider is described as "used for testing" + * in the user manual. So it's not modelled and forced to 0. + */ +#define SUN50I_H616_PLL_VIDEO0_REG 0x040 +static struct ccu_nm pll_video0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .min_rate = 288000000, + .max_rate = 2400000000UL, + .common = { + .reg = 0x040, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video0", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_VIDEO1_REG 0x048 +static struct ccu_nm pll_video1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .min_rate = 288000000, + .max_rate = 2400000000UL, + .common = { + .reg = 0x048, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video1", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_VIDEO2_REG 0x050 +static struct ccu_nm pll_video2_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .min_rate = 288000000, + .max_rate = 2400000000UL, + .common = { + .reg = 0x050, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video2", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_VE_REG 0x058 +static struct ccu_nkmp pll_ve_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x058, + .hw.init = CLK_HW_INIT("pll-ve", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_H616_PLL_DE_REG 0x060 +static struct ccu_nkmp pll_de_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x060, + .hw.init = CLK_HW_INIT("pll-de", "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * TODO: Determine SDM settings for the audio PLL. The manual suggests + * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b + * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, + * pattern=0xe001288c for 22.5792 MHz. + * This clashes with our fixed PLL_POST_DIV_P. + */ +#define SUN50I_H616_PLL_AUDIO_REG 0x078 +static struct ccu_nm pll_audio_hs_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .common = { + .reg = 0x078, + .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const char * const cpux_parents[] = { "osc24M", "osc32k", + "iosc", "pll-cpux", "pll-periph0" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); + +static const char * const psi_ahb1_ahb2_parents[] = { "osc24M", "osc32k", + "iosc", "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", + psi_ahb1_ahb2_parents, + 0x510, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const ahb3_apb1_apb2_parents[] = { "osc24M", "osc32k", + "psi-ahb1-ahb2", + "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", + "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, + 0, 3, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static const char * const de_parents[] = { "pll-de", "pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, 0x600, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", + 0x60c, BIT(0), 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", + de_parents, + 0x620, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "psi-ahb1-ahb2", + 0x62c, BIT(0), 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", de_parents, 0x630, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", + 0x63c, BIT(0), 0); + +static const char * const gpu0_parents[] = { "pll-gpu", "gpu1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(gpu0_clk, "gpu0", gpu0_parents, 0x670, + 0, 2, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_GATE(gpu1_clk, "gpu1", "pll-periph0-2x", 0x674, + 0, 3, /* M */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", + 0x67c, BIT(0), 0); + +static const char * const ce_parents[] = { "osc24M", "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", + 0x68c, BIT(0), 0); + +static const char * const ve_parents[] = { "pll-ve" }; +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, + 0, 3, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", + 0x69c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", + 0x70c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", + 0x73c, BIT(0), 0); + +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x740, BIT(31), 0); + +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", + 0x78c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", + 0x79c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); + +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; +static struct ccu_div dram_clk = { + .div = _SUNXI_CCU_DIV(0, 2), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0x800, + .hw.init = CLK_HW_INIT_PARENTS("dram", + dram_parents, + &ccu_div_ops, + CLK_IS_CRITICAL), + }, +}; + +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", + 0x804, BIT(0), 0); +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", + 0x804, BIT(1), 0); +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", + 0x804, BIT(2), 0); +static SUNXI_CCU_GATE(mbus_ts_clk, "mbus-ts", "mbus", + 0x804, BIT(3), 0); +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", + 0x804, BIT(5), 0); +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", + 0x804, BIT(10), 0); + +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", + 0x80c, BIT(0), CLK_IS_CRITICAL); + +static const char * const nand_spi_parents[] = { "osc24M", "pll-periph0", + "pll-periph1", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); + +static const char * const mmc_parents[] = { "osc24M", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + 0); + +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); + +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0); +static SUNXI_CCU_GATE(bus_uart5_clk, "bus-uart5", "apb2", 0x90c, BIT(5), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_i2c4_clk, "bus-i2c4", "apb2", 0x91c, BIT(4), 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 3, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); + +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, + BIT(31) | BIT(30), 0); + +static SUNXI_CCU_GATE(bus_emac0_clk, "bus-emac0", "ahb3", 0x97c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_emac1_clk, "bus-emac1", "ahb3", 0x97c, BIT(1), 0); + +static const char * const ts_parents[] = { "osc24M", "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x9b0, + 0, 4, /* M */ + 8, 2, /* N */ + 24, 1, /* mux */ + BIT(31),/* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb3", 0x9bc, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); + +static const char * const audio_parents[] = { "pll-audio-1x", "pll-audio-2x", + "pll-audio-4x", "pll-audio-hs" }; +static struct ccu_div spdif_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa20, + .hw.init = CLK_HW_INIT_PARENTS("spdif", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); + +static struct ccu_div dmic_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa40, + .hw.init = CLK_HW_INIT_PARENTS("dmic", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_1x_clk, "audio-codec-1x", + audio_parents, 0xa50, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", + audio_parents, 0xa54, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c, + BIT(0), 0); + +static struct ccu_div audio_hub_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa60, + .hw.init = CLK_HW_INIT_PARENTS("audio-hub", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_audio_hub_clk, "bus-audio-hub", "apb1", 0xa6c, BIT(0), 0); + +/* + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. + * We will force them to 0 (12M divided from 48M). + */ +#define SUN50I_H616_USB0_CLK_REG 0xa70 +#define SUN50I_H616_USB1_CLK_REG 0xa74 +#define SUN50I_H616_USB2_CLK_REG 0xa78 +#define SUN50I_H616_USB3_CLK_REG 0xa7c + +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0xa70, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", 0xa74, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc12M", 0xa78, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy2_clk, "usb-phy2", "osc24M", 0xa78, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc12M", 0xa7c, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy3_clk, "usb-phy3", "osc12M", 0xa7c, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_ohci2_clk, "bus-ohci2", "ahb3", 0xa8c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_ohci3_clk, "bus-ohci3", "ahb3", 0xa8c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ehci2_clk, "bus-ehci2", "ahb3", 0xa8c, BIT(6), 0); +static SUNXI_CCU_GATE(bus_ehci3_clk, "bus-ehci3", "ahb3", 0xa8c, BIT(7), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); + +static SUNXI_CCU_GATE(bus_keyadc_clk, "bus-keyadc", "apb1", 0xa9c, BIT(0), 0); + +static struct clk_fixed_factor pll_periph0_4x_clk; + +static const char * const hdmi_parents[] = { "pll-video0", "pll-video0-4x", + "pll-video2", "pll-video2-4x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, 0xb00, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0xb04, BIT(31), 0); + +static const char * const hdmi_cec_parents[] = { "osc32k", "pll-periph0-2x" }; +static const struct ccu_mux_fixed_prediv hdmi_cec_predivs[] = { + { .index = 1, .div = 36621 }, +}; + +#define SUN50I_H616_HDMI_CEC_CLK_REG 0xb10 +static struct ccu_mux hdmi_cec_clk = { + .enable = BIT(31), + + .mux = { + .shift = 24, + .width = 2, + + .fixed_predivs = hdmi_cec_predivs, + .n_predivs = ARRAY_SIZE(hdmi_cec_predivs), + }, + + .common = { + .reg = 0xb10, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("hdmi-cec", + hdmi_cec_parents, + &ccu_mux_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb3", 0xb1c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_tcon_top_clk, "bus-tcon-top", "ahb3", + 0xb5c, BIT(0), 0); + +static const char * const tcon_tv0_parents[] = { "pll-video0", + "pll-video0-4x", + "pll-video1", + "pll-video1-4x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", + tcon_tv0_parents, 0xb80, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_tcon_tv0_clk, "bus-tcon-tv0", "ahb3", + 0xb9c, BIT(0), 0); + +static const char * const hdcp_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdcp_clk, "hdcp", hdcp_parents, 0xc40, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_hdcp_clk, "bus-hdcp", "ahb3", 0xc4c, BIT(0), 0); + +/* Fixed factor clocks */ +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); + +static const struct clk_hw *clk_parent_pll_audio[] = { + &pll_audio_hs_clk.common.hw +}; + +/* + * The divider of pll-audio is fixed to 24 for now, so 24576000 and 22579200 + * rates can be set exactly in conjunction with sigma-delta modulation. + */ +static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", + clk_parent_pll_audio, + 96, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", + clk_parent_pll_audio, + 48, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", + clk_parent_pll_audio, + 24, 1, CLK_SET_RATE_PARENT); + +static const struct clk_hw *pll_periph0_parents[] = { + &pll_periph0_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_periph0_4x_clk, "pll-periph0-4x", + pll_periph0_parents, + 1, 4, 0); +static CLK_FIXED_FACTOR_HWS(pll_periph0_2x_clk, "pll-periph0-2x", + pll_periph0_parents, + 1, 2, 0); + +static const struct clk_hw *pll_periph1_parents[] = { + &pll_periph1_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_periph1_4x_clk, "pll-periph1-4x", + pll_periph1_parents, + 1, 4, 0); +static CLK_FIXED_FACTOR_HWS(pll_periph1_2x_clk, "pll-periph1-2x", + pll_periph1_parents, + 1, 2, 0); + +static CLK_FIXED_FACTOR_HW(pll_video0_4x_clk, "pll-video0-4x", + &pll_video0_clk.common.hw, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HW(pll_video1_4x_clk, "pll-video1-4x", + &pll_video1_clk.common.hw, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HW(pll_video2_4x_clk, "pll-video2-4x", + &pll_video2_clk.common.hw, + 1, 4, CLK_SET_RATE_PARENT); + +static struct ccu_common *sun50i_h616_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_ddr0_clk.common, + &pll_ddr1_clk.common, + &pll_periph0_clk.common, + &pll_periph1_clk.common, + &pll_gpu_clk.common, + &pll_video0_clk.common, + &pll_video1_clk.common, + &pll_video2_clk.common, + &pll_ve_clk.common, + &pll_de_clk.common, + &pll_audio_hs_clk.common, + &cpux_clk.common, + &axi_clk.common, + &cpux_apb_clk.common, + &psi_ahb1_ahb2_clk.common, + &ahb3_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &mbus_clk.common, + &de_clk.common, + &bus_de_clk.common, + &deinterlace_clk.common, + &bus_deinterlace_clk.common, + &g2d_clk.common, + &bus_g2d_clk.common, + &gpu0_clk.common, + &bus_gpu_clk.common, + &gpu1_clk.common, + &ce_clk.common, + &bus_ce_clk.common, + &ve_clk.common, + &bus_ve_clk.common, + &bus_dma_clk.common, + &bus_hstimer_clk.common, + &avs_clk.common, + &bus_dbg_clk.common, + &bus_psi_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_ts_clk.common, + &mbus_nand_clk.common, + &mbus_g2d_clk.common, + &bus_dram_clk.common, + &nand0_clk.common, + &nand1_clk.common, + &bus_nand_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_uart4_clk.common, + &bus_uart5_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, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &emac_25m_clk.common, + &bus_emac0_clk.common, + &bus_emac1_clk.common, + &ts_clk.common, + &bus_ts_clk.common, + &bus_ths_clk.common, + &spdif_clk.common, + &bus_spdif_clk.common, + &dmic_clk.common, + &bus_dmic_clk.common, + &audio_codec_1x_clk.common, + &audio_codec_4x_clk.common, + &bus_audio_codec_clk.common, + &audio_hub_clk.common, + &bus_audio_hub_clk.common, + &usb_ohci0_clk.common, + &usb_phy0_clk.common, + &usb_ohci1_clk.common, + &usb_phy1_clk.common, + &usb_ohci2_clk.common, + &usb_phy2_clk.common, + &usb_ohci3_clk.common, + &usb_phy3_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ohci2_clk.common, + &bus_ohci3_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_ehci2_clk.common, + &bus_ehci3_clk.common, + &bus_otg_clk.common, + &bus_keyadc_clk.common, + &hdmi_clk.common, + &hdmi_slow_clk.common, + &hdmi_cec_clk.common, + &bus_hdmi_clk.common, + &bus_tcon_top_clk.common, + &tcon_tv0_clk.common, + &bus_tcon_tv0_clk.common, + &hdcp_clk.common, + &bus_hdcp_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_h616_hw_clks = { + .hws = { + [CLK_OSC12M] = &osc12M_clk.hw, + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, + [CLK_PLL_PERIPH1_4X] = &pll_periph1_4x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_PLL_AUDIO_HS] = &pll_audio_hs_clk.common.hw, + [CLK_PLL_AUDIO_1X] = &pll_audio_1x_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw, + [CLK_AHB3] = &ahb3_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, + [CLK_G2D] = &g2d_clk.common.hw, + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, + [CLK_GPU0] = &gpu0_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_GPU1] = &gpu1_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_BUS_DMA] = &bus_dma_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_PSI] = &bus_psi_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_TS] = &mbus_ts_clk.common.hw, + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_NAND0] = &nand0_clk.common.hw, + [CLK_NAND1] = &nand1_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_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_UART4] = &bus_uart4_clk.common.hw, + [CLK_BUS_UART5] = &bus_uart5_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_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, + [CLK_BUS_EMAC0] = &bus_emac0_clk.common.hw, + [CLK_BUS_EMAC1] = &bus_emac1_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_BUS_TS] = &bus_ts_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_DMIC] = &dmic_clk.common.hw, + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, + [CLK_AUDIO_CODEC_1X] = &audio_codec_1x_clk.common.hw, + [CLK_AUDIO_CODEC_4X] = &audio_codec_4x_clk.common.hw, + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw, + [CLK_AUDIO_HUB] = &audio_hub_clk.common.hw, + [CLK_BUS_AUDIO_HUB] = &bus_audio_hub_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_KEYADC] = &bus_keyadc_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw, + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_BUS_TCON_TOP] = &bus_tcon_top_clk.common.hw, + [CLK_TCON_TV0] = &tcon_tv0_clk.common.hw, + [CLK_BUS_TCON_TV0] = &bus_tcon_tv0_clk.common.hw, + [CLK_HDCP] = &hdcp_clk.common.hw, + [CLK_BUS_HDCP] = &bus_hdcp_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_h616_ccu_resets[] = { + [RST_MBUS] = { 0x540, BIT(30) }, + + [RST_BUS_DE] = { 0x60c, BIT(16) }, + [RST_BUS_DEINTERLACE] = { 0x62c, BIT(16) }, + [RST_BUS_GPU] = { 0x67c, BIT(16) }, + [RST_BUS_CE] = { 0x68c, BIT(16) }, + [RST_BUS_VE] = { 0x69c, BIT(16) }, + [RST_BUS_DMA] = { 0x70c, BIT(16) }, + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, + [RST_BUS_DBG] = { 0x78c, BIT(16) }, + [RST_BUS_PSI] = { 0x79c, BIT(16) }, + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, + [RST_BUS_IOMMU] = { 0x7bc, BIT(16) }, + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, + [RST_BUS_NAND] = { 0x82c, 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_UART4] = { 0x90c, BIT(20) }, + [RST_BUS_UART5] = { 0x90c, BIT(21) }, + [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_EMAC0] = { 0x97c, BIT(16) }, + [RST_BUS_EMAC1] = { 0x97c, BIT(17) }, + [RST_BUS_TS] = { 0x9bc, BIT(16) }, + [RST_BUS_THS] = { 0x9fc, BIT(16) }, + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, + [RST_BUS_AUDIO_HUB] = { 0xa6c, BIT(16) }, + + [RST_USB_PHY0] = { 0xa70, BIT(30) }, + [RST_USB_PHY1] = { 0xa74, BIT(30) }, + [RST_USB_PHY2] = { 0xa78, BIT(30) }, + [RST_USB_PHY3] = { 0xa7c, BIT(30) }, + + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, + [RST_BUS_OHCI2] = { 0xa8c, BIT(18) }, + [RST_BUS_OHCI3] = { 0xa8c, BIT(19) }, + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, + [RST_BUS_EHCI2] = { 0xa8c, BIT(22) }, + [RST_BUS_EHCI3] = { 0xa8c, BIT(23) }, + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, + [RST_BUS_KEYADC] = { 0xa9c, BIT(16) }, + + [RST_BUS_HDMI] = { 0xb1c, BIT(16) }, + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, + [RST_BUS_TCON_TOP] = { 0xb5c, BIT(16) }, + [RST_BUS_TCON_TV0] = { 0xb9c, BIT(16) }, + [RST_BUS_HDCP] = { 0xc4c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun50i_h616_ccu_desc = { + .ccu_clks = sun50i_h616_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_h616_ccu_clks), + + .hw_clks = &sun50i_h616_hw_clks, + + .resets = sun50i_h616_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_h616_ccu_resets), +}; + +static const u32 pll_regs[] = { + SUN50I_H616_PLL_CPUX_REG, + SUN50I_H616_PLL_DDR0_REG, + SUN50I_H616_PLL_DDR1_REG, + SUN50I_H616_PLL_PERIPH0_REG, + SUN50I_H616_PLL_PERIPH1_REG, + SUN50I_H616_PLL_GPU_REG, + SUN50I_H616_PLL_VIDEO0_REG, + SUN50I_H616_PLL_VIDEO1_REG, + SUN50I_H616_PLL_VIDEO2_REG, + SUN50I_H616_PLL_VE_REG, + SUN50I_H616_PLL_DE_REG, + SUN50I_H616_PLL_AUDIO_REG, +}; + +static const u32 pll_video_regs[] = { + SUN50I_H616_PLL_VIDEO0_REG, + SUN50I_H616_PLL_VIDEO1_REG, + SUN50I_H616_PLL_VIDEO2_REG, +}; + +static const u32 usb2_clk_regs[] = { + SUN50I_H616_USB0_CLK_REG, + SUN50I_H616_USB1_CLK_REG, + SUN50I_H616_USB2_CLK_REG, + SUN50I_H616_USB3_CLK_REG, +}; + +static int sun50i_h616_ccu_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *reg; + u32 val; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* Enable the lock bits on all PLLs */ + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { + val = readl(reg + pll_regs[i]); + val |= BIT(29); + writel(val, reg + pll_regs[i]); + } + + /* + * Force the output divider of video PLLs to 0. + * + * See the comment before pll-video0 definition for the reason. + */ + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { + val = readl(reg + pll_video_regs[i]); + val &= ~BIT(0); + writel(val, reg + pll_video_regs[i]); + } + + /* + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) + * + * This clock mux is still mysterious, and the code just enforces + * it to have a valid clock parent. + */ + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) { + val = readl(reg + usb2_clk_regs[i]); + val &= ~GENMASK(25, 24); + writel (val, reg + usb2_clk_regs[i]); + } + + /* + * Force the post-divider of pll-audio to 12 and the output divider + * of it to 2, so 24576000 and 22579200 rates can be set exactly. + */ + val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); + val &= ~(GENMASK(21, 16) | BIT(0)); + writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG); + + /* + * First clock parent (osc32K) is unusable for CEC. But since there + * is no good way to force parent switch (both run with same frequency), + * just set second clock parent here. + */ + val = readl(reg + SUN50I_H616_HDMI_CEC_CLK_REG); + val |= BIT(24); + writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); + + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h616_ccu_desc); +} + +static const struct of_device_id sun50i_h616_ccu_ids[] = { + { .compatible = "allwinner,sun50i-h616-ccu", + .data = &sun50i_h616_ccu_desc }, + { } +}; + +static struct platform_driver sun50i_h616_ccu_driver = { + .probe = sun50i_h616_ccu_probe, + .driver = { + .name = "sun50i-h616-ccu", + .of_match_table = sun50i_h616_ccu_ids, + }, +}; +builtin_platform_driver(sun50i_h616_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.h b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h new file mode 100644 index 000000000000..da8f0b1206f9 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2020 Arm Ltd. + */ + +#ifndef _CCU_SUN50I_H616_H_ +#define _CCU_SUN50I_H616_H_ + +#include <dt-bindings/clock/sun50i-h616-ccu.h> +#include <dt-bindings/reset/sun50i-h616-ccu.h> + +#define CLK_OSC12M 0 +#define CLK_PLL_CPUX 1 +#define CLK_PLL_DDR0 2 +#define CLK_PLL_DDR1 3 + +/* PLL_PERIPH0 exported for PRCM */ + +#define CLK_PLL_PERIPH0_2X 5 +#define CLK_PLL_PERIPH0_4X 6 +#define CLK_PLL_PERIPH1 7 +#define CLK_PLL_PERIPH1_2X 8 +#define CLK_PLL_PERIPH1_4X 9 +#define CLK_PLL_GPU 10 +#define CLK_PLL_VIDEO0 11 +#define CLK_PLL_VIDEO0_4X 12 +#define CLK_PLL_VIDEO1 13 +#define CLK_PLL_VIDEO1_4X 14 +#define CLK_PLL_VIDEO2 15 +#define CLK_PLL_VIDEO2_4X 16 +#define CLK_PLL_VE 17 +#define CLK_PLL_DE 18 +#define CLK_PLL_AUDIO_HS 19 +#define CLK_PLL_AUDIO_1X 20 +#define CLK_PLL_AUDIO_2X 21 +#define CLK_PLL_AUDIO_4X 22 + +/* CPUX clock exported for DVFS */ + +#define CLK_AXI 24 +#define CLK_CPUX_APB 25 +#define CLK_PSI_AHB1_AHB2 26 +#define CLK_AHB3 27 + +/* APB1 clock exported for PIO */ + +#define CLK_APB2 29 +#define CLK_MBUS 30 + +/* All module clocks and bus gates are exported except DRAM */ + +#define CLK_DRAM 51 + +#define CLK_BUS_DRAM 58 + +#define CLK_NUMBER (CLK_BUS_HDCP + 1) + +#endif /* _CCU_SUN50I_H616_H_ */ diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h b/include/dt-bindings/clock/sun50i-h616-ccu.h new file mode 100644 index 000000000000..a9cc8844e3a9 --- /dev/null +++ b/include/dt-bindings/clock/sun50i-h616-ccu.h @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2020 Arm Ltd. + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_ +#define _DT_BINDINGS_CLK_SUN50I_H616_H_ + +#define CLK_PLL_PERIPH0 4 + +#define CLK_CPUX 23 + +#define CLK_APB1 28 + +#define CLK_DE 31 +#define CLK_BUS_DE 32 +#define CLK_DEINTERLACE 33 +#define CLK_BUS_DEINTERLACE 34 +#define CLK_G2D 35 +#define CLK_BUS_G2D 36 +#define CLK_GPU0 37 +#define CLK_BUS_GPU 38 +#define CLK_GPU1 39 +#define CLK_CE 40 +#define CLK_BUS_CE 41 +#define CLK_VE 42 +#define CLK_BUS_VE 43 +#define CLK_BUS_DMA 44 +#define CLK_BUS_HSTIMER 45 +#define CLK_AVS 46 +#define CLK_BUS_DBG 47 +#define CLK_BUS_PSI 48 +#define CLK_BUS_PWM 49 +#define CLK_BUS_IOMMU 50 + +#define CLK_MBUS_DMA 52 +#define CLK_MBUS_VE 53 +#define CLK_MBUS_CE 54 +#define CLK_MBUS_TS 55 +#define CLK_MBUS_NAND 56 +#define CLK_MBUS_G2D 57 + +#define CLK_NAND0 59 +#define CLK_NAND1 60 +#define CLK_BUS_NAND 61 +#define CLK_MMC0 62 +#define CLK_MMC1 63 +#define CLK_MMC2 64 +#define CLK_BUS_MMC0 65 +#define CLK_BUS_MMC1 66 +#define CLK_BUS_MMC2 67 +#define CLK_BUS_UART0 68 +#define CLK_BUS_UART1 69 +#define CLK_BUS_UART2 70 +#define CLK_BUS_UART3 71 +#define CLK_BUS_UART4 72 +#define CLK_BUS_UART5 73 +#define CLK_BUS_I2C0 74 +#define CLK_BUS_I2C1 75 +#define CLK_BUS_I2C2 76 +#define CLK_BUS_I2C3 77 +#define CLK_BUS_I2C4 78 +#define CLK_SPI0 79 +#define CLK_SPI1 80 +#define CLK_BUS_SPI0 81 +#define CLK_BUS_SPI1 82 +#define CLK_EMAC_25M 83 +#define CLK_BUS_EMAC0 84 +#define CLK_BUS_EMAC1 85 +#define CLK_TS 86 +#define CLK_BUS_TS 87 +#define CLK_BUS_THS 88 +#define CLK_SPDIF 89 +#define CLK_BUS_SPDIF 90 +#define CLK_DMIC 91 +#define CLK_BUS_DMIC 92 +#define CLK_AUDIO_CODEC_1X 93 +#define CLK_AUDIO_CODEC_4X 94 +#define CLK_BUS_AUDIO_CODEC 95 +#define CLK_AUDIO_HUB 96 +#define CLK_BUS_AUDIO_HUB 97 +#define CLK_USB_OHCI0 98 +#define CLK_USB_PHY0 99 +#define CLK_USB_OHCI1 100 +#define CLK_USB_PHY1 101 +#define CLK_USB_OHCI2 102 +#define CLK_USB_PHY2 103 +#define CLK_USB_OHCI3 104 +#define CLK_USB_PHY3 105 +#define CLK_BUS_OHCI0 106 +#define CLK_BUS_OHCI1 107 +#define CLK_BUS_OHCI2 108 +#define CLK_BUS_OHCI3 109 +#define CLK_BUS_EHCI0 110 +#define CLK_BUS_EHCI1 111 +#define CLK_BUS_EHCI2 112 +#define CLK_BUS_EHCI3 113 +#define CLK_BUS_OTG 114 +#define CLK_BUS_KEYADC 115 +#define CLK_HDMI 116 +#define CLK_HDMI_SLOW 117 +#define CLK_HDMI_CEC 118 +#define CLK_BUS_HDMI 119 +#define CLK_BUS_TCON_TOP 120 +#define CLK_TCON_TV0 121 +#define CLK_BUS_TCON_TV0 122 +#define CLK_HDCP 123 +#define CLK_BUS_HDCP 124 + +#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */ diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h b/include/dt-bindings/reset/sun50i-h616-ccu.h new file mode 100644 index 000000000000..1c992cfbbbab --- /dev/null +++ b/include/dt-bindings/reset/sun50i-h616-ccu.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: (GPL-2.0+ or MIT) +/* + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io> + */ + +#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_ +#define _DT_BINDINGS_RESET_SUN50I_H616_H_ + +#define RST_MBUS 0 +#define RST_BUS_DE 1 +#define RST_BUS_DEINTERLACE 2 +#define RST_BUS_GPU 3 +#define RST_BUS_CE 4 +#define RST_BUS_VE 5 +#define RST_BUS_DMA 6 +#define RST_BUS_HSTIMER 7 +#define RST_BUS_DBG 8 +#define RST_BUS_PSI 9 +#define RST_BUS_PWM 10 +#define RST_BUS_IOMMU 11 +#define RST_BUS_DRAM 12 +#define RST_BUS_NAND 13 +#define RST_BUS_MMC0 14 +#define RST_BUS_MMC1 15 +#define RST_BUS_MMC2 16 +#define RST_BUS_UART0 17 +#define RST_BUS_UART1 18 +#define RST_BUS_UART2 19 +#define RST_BUS_UART3 20 +#define RST_BUS_UART4 21 +#define RST_BUS_UART5 22 +#define RST_BUS_I2C0 23 +#define RST_BUS_I2C1 24 +#define RST_BUS_I2C2 25 +#define RST_BUS_I2C3 26 +#define RST_BUS_I2C4 27 +#define RST_BUS_SPI0 28 +#define RST_BUS_SPI1 29 +#define RST_BUS_EMAC0 30 +#define RST_BUS_EMAC1 31 +#define RST_BUS_TS 32 +#define RST_BUS_THS 33 +#define RST_BUS_SPDIF 34 +#define RST_BUS_DMIC 35 +#define RST_BUS_AUDIO_CODEC 36 +#define RST_BUS_AUDIO_HUB 37 +#define RST_USB_PHY0 38 +#define RST_USB_PHY1 39 +#define RST_USB_PHY2 40 +#define RST_USB_PHY3 41 +#define RST_BUS_OHCI0 42 +#define RST_BUS_OHCI1 43 +#define RST_BUS_OHCI2 44 +#define RST_BUS_OHCI3 45 +#define RST_BUS_EHCI0 46 +#define RST_BUS_EHCI1 47 +#define RST_BUS_EHCI2 48 +#define RST_BUS_EHCI3 49 +#define RST_BUS_OTG 50 +#define RST_BUS_HDMI 51 +#define RST_BUS_HDMI_SUB 52 +#define RST_BUS_TCON_TOP 53 +#define RST_BUS_TCON_TV0 54 +#define RST_BUS_HDCP 55 +#define RST_BUS_KEYADC 56 + +#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */
While the clocks are fairly similar to the H6, many differ in tiny details, so a separate clock driver seems indicated. Derived from the H6 clock driver, and adjusted according to the manual. Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- drivers/clk/sunxi-ng/Kconfig | 7 +- drivers/clk/sunxi-ng/Makefile | 1 + drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 1134 +++++++++++++++++++ drivers/clk/sunxi-ng/ccu-sun50i-h616.h | 58 + include/dt-bindings/clock/sun50i-h616-ccu.h | 110 ++ include/dt-bindings/reset/sun50i-h616-ccu.h | 67 ++ 6 files changed, 1376 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-h616.h create mode 100644 include/dt-bindings/clock/sun50i-h616-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-h616-ccu.h