diff mbox series

[5/8] clk: sunxi-ng: Add support for the Allwinner H616 CCU

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

Commit Message

Andre Przywara Dec. 2, 2020, 1:54 p.m. UTC
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

Comments

Maxime Ripard Dec. 2, 2020, 3:56 p.m. UTC | #1
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
Jernej Škrabec Dec. 2, 2020, 9:03 p.m. UTC | #2
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
> 
> 
>
Andre Przywara Dec. 2, 2020, 11:06 p.m. UTC | #3
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
>>
>>
>>
> 
>
Icenowy Zheng Dec. 5, 2020, 4:36 p.m. UTC | #4
在 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
> > > 
> > > 
> > >
Clément Péron Dec. 9, 2020, 2:33 p.m. UTC | #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.
Andre Przywara Dec. 9, 2020, 9:35 p.m. UTC | #6
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
Jernej Škrabec Dec. 9, 2020, 10:20 p.m. UTC | #7
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
Andre Przywara Dec. 9, 2020, 10:45 p.m. UTC | #8
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
> 
> 
> 
> 
>
Icenowy Zheng Dec. 10, 2020, 1:31 p.m. UTC | #9
在 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
>
Andre Przywara Dec. 10, 2020, 2:34 p.m. UTC | #10
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 mbox series

Patch

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_ */