From 4617721c502b2ddaa4e324e86da4997edf738fa5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2026 09:55:01 -0400 Subject: ftrace: Synchronize the initialization of ftrace_ops There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt --- drivers/clk/meson/Kconfig | 259 ++ drivers/clk/meson/Makefile | 32 + drivers/clk/meson/a1-peripherals.c | 2099 +++++++++++++ drivers/clk/meson/a1-pll.c | 326 ++ drivers/clk/meson/a9-aoclk.c | 489 +++ drivers/clk/meson/a9-peripherals.c | 2089 +++++++++++++ drivers/clk/meson/axg-aoclk.c | 320 ++ drivers/clk/meson/axg-audio.c | 1448 +++++++++ drivers/clk/meson/axg.c | 2148 +++++++++++++ drivers/clk/meson/c3-peripherals.c | 1128 +++++++ drivers/clk/meson/c3-pll.c | 684 +++++ drivers/clk/meson/clk-cpu-dyndiv.c | 74 + drivers/clk/meson/clk-cpu-dyndiv.h | 20 + drivers/clk/meson/clk-dualdiv.c | 146 + drivers/clk/meson/clk-dualdiv.h | 33 + drivers/clk/meson/clk-mpll.c | 176 ++ drivers/clk/meson/clk-mpll.h | 32 + drivers/clk/meson/clk-phase.c | 197 ++ drivers/clk/meson/clk-phase.h | 32 + drivers/clk/meson/clk-pll.c | 507 ++++ drivers/clk/meson/clk-pll.h | 54 + drivers/clk/meson/clk-regmap.c | 236 ++ drivers/clk/meson/clk-regmap.h | 121 + drivers/clk/meson/g12a-aoclk.c | 446 +++ drivers/clk/meson/g12a.c | 5473 ++++++++++++++++++++++++++++++++++ drivers/clk/meson/gxbb-aoclk.c | 278 ++ drivers/clk/meson/gxbb.c | 3297 ++++++++++++++++++++ drivers/clk/meson/meson-aoclk.c | 88 + drivers/clk/meson/meson-aoclk.h | 36 + drivers/clk/meson/meson-clkc-utils.c | 111 + drivers/clk/meson/meson-clkc-utils.h | 108 + drivers/clk/meson/meson8-ddr.c | 112 + drivers/clk/meson/meson8b.c | 3720 +++++++++++++++++++++++ drivers/clk/meson/parm.h | 46 + drivers/clk/meson/s4-peripherals.c | 3259 ++++++++++++++++++++ drivers/clk/meson/s4-pll.c | 831 ++++++ drivers/clk/meson/sclk-div.c | 260 ++ drivers/clk/meson/sclk-div.h | 22 + drivers/clk/meson/t7-peripherals.c | 1271 ++++++++ drivers/clk/meson/t7-pll.c | 1074 +++++++ drivers/clk/meson/vclk.c | 144 + drivers/clk/meson/vclk.h | 51 + drivers/clk/meson/vid-pll-div.c | 101 + drivers/clk/meson/vid-pll-div.h | 20 + 44 files changed, 33398 insertions(+) create mode 100644 drivers/clk/meson/Kconfig create mode 100644 drivers/clk/meson/Makefile create mode 100644 drivers/clk/meson/a1-peripherals.c create mode 100644 drivers/clk/meson/a1-pll.c create mode 100644 drivers/clk/meson/a9-aoclk.c create mode 100644 drivers/clk/meson/a9-peripherals.c create mode 100644 drivers/clk/meson/axg-aoclk.c create mode 100644 drivers/clk/meson/axg-audio.c create mode 100644 drivers/clk/meson/axg.c create mode 100644 drivers/clk/meson/c3-peripherals.c create mode 100644 drivers/clk/meson/c3-pll.c create mode 100644 drivers/clk/meson/clk-cpu-dyndiv.c create mode 100644 drivers/clk/meson/clk-cpu-dyndiv.h create mode 100644 drivers/clk/meson/clk-dualdiv.c create mode 100644 drivers/clk/meson/clk-dualdiv.h create mode 100644 drivers/clk/meson/clk-mpll.c create mode 100644 drivers/clk/meson/clk-mpll.h create mode 100644 drivers/clk/meson/clk-phase.c create mode 100644 drivers/clk/meson/clk-phase.h create mode 100644 drivers/clk/meson/clk-pll.c create mode 100644 drivers/clk/meson/clk-pll.h create mode 100644 drivers/clk/meson/clk-regmap.c create mode 100644 drivers/clk/meson/clk-regmap.h create mode 100644 drivers/clk/meson/g12a-aoclk.c create mode 100644 drivers/clk/meson/g12a.c create mode 100644 drivers/clk/meson/gxbb-aoclk.c create mode 100644 drivers/clk/meson/gxbb.c create mode 100644 drivers/clk/meson/meson-aoclk.c create mode 100644 drivers/clk/meson/meson-aoclk.h create mode 100644 drivers/clk/meson/meson-clkc-utils.c create mode 100644 drivers/clk/meson/meson-clkc-utils.h create mode 100644 drivers/clk/meson/meson8-ddr.c create mode 100644 drivers/clk/meson/meson8b.c create mode 100644 drivers/clk/meson/parm.h create mode 100644 drivers/clk/meson/s4-peripherals.c create mode 100644 drivers/clk/meson/s4-pll.c create mode 100644 drivers/clk/meson/sclk-div.c create mode 100644 drivers/clk/meson/sclk-div.h create mode 100644 drivers/clk/meson/t7-peripherals.c create mode 100644 drivers/clk/meson/t7-pll.c create mode 100644 drivers/clk/meson/vclk.c create mode 100644 drivers/clk/meson/vclk.h create mode 100644 drivers/clk/meson/vid-pll-div.c create mode 100644 drivers/clk/meson/vid-pll-div.h (limited to 'drivers/clk/meson') diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig new file mode 100644 index 000000000..d460514bb --- /dev/null +++ b/drivers/clk/meson/Kconfig @@ -0,0 +1,259 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "Clock support for Amlogic platforms" + depends on ARCH_MESON || COMPILE_TEST + +config COMMON_CLK_MESON_REGMAP + tristate + select REGMAP + select MFD_SYSCON + +config COMMON_CLK_MESON_DUALDIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_MPLL + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_PHASE + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_PLL + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_SCLK_DIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_VID_PLL_DIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_VCLK + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_CLKC_UTILS + select REGMAP + select MFD_SYSCON + tristate + +config COMMON_CLK_MESON_AO_CLKC + tristate + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select RESET_CONTROLLER + +config COMMON_CLK_MESON_CPU_DYNDIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON8B + bool "Meson8 SoC Clock controller support" + depends on ARM + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select MFD_SYSCON + select RESET_CONTROLLER + help + Support for the clock controller on AmLogic S802 (Meson8), + S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you + want peripherals and CPU frequency scaling to work. + +config COMMON_CLK_GXBB + tristate "GXBB and GXL SoC clock controllers support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_VID_PLL_DIV + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC + select MFD_SYSCON + help + Support for the clock controller on AmLogic S905 devices, aka gxbb. + Say Y if you want peripherals and CPU frequency scaling to work. + +config COMMON_CLK_AXG + tristate "AXG SoC clock controllers support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC + select MFD_SYSCON + help + Support for the clock controller on AmLogic A113D devices, aka axg. + Say Y if you want peripherals and CPU frequency scaling to work. + +config COMMON_CLK_AXG_AUDIO + tristate "Meson AXG Audio Clock Controller Driver" + depends on ARM64 + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_PHASE + select COMMON_CLK_MESON_SCLK_DIV + select COMMON_CLK_MESON_CLKC_UTILS + select REGMAP_MMIO + select AUXILIARY_BUS + imply RESET_MESON_AUX + help + Support for the audio clock controller on AmLogic A113D devices, + aka axg, Say Y if you want audio subsystem to work. + +config COMMON_CLK_A1_PLL + tristate "Amlogic A1 SoC PLL controller support" + depends on ARM64 + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_PLL + help + Support for the PLL clock controller on Amlogic A113L based + device, A1 SoC Family. Say Y if you want A1 PLL clock controller + to work. + +config COMMON_CLK_A1_PERIPHERALS + tristate "Amlogic A1 SoC Peripherals clock controller support" + depends on ARM64 + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + help + Support for the Peripherals clock controller on Amlogic A113L based + device, A1 SoC Family. Say Y if you want A1 Peripherals clock + controller to work. + +config COMMON_CLK_A9_PERIPHERALS + tristate "Amlogic A9 SoC peripherals clock controller support" + depends on ARM64 || COMPILE_TEST + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_VID_PLL_DIV + imply COMMON_CLK_SCMI + help + Support for the peripherals clock controller on Amlogic A311Y3 based + device, AKA A9. Peripherals are required by most peripheral to operate. + Say Y if you want A9 peripherals clock controller to work. + +config COMMON_CLK_A9_AO + tristate "Amlogic A9 SoC AO clock controller support" + depends on ARM64 || COMPILE_TEST + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + imply COMMON_CLK_SCMI + help + Support for the AO clock controller on Amlogic A311Y3 based + device, AKA A9. + Say Y if you want A9 AO clock controller to work. + +config COMMON_CLK_C3_PLL + tristate "Amlogic C3 PLL clock controller" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_CLKC_UTILS + imply COMMON_CLK_SCMI + help + Support for the PLL clock controller on Amlogic C302X and C308L devices, + AKA C3. Say Y if you want the board to work, because PLLs are the parent + of most peripherals. + +config COMMON_CLK_C3_PERIPHERALS + tristate "Amlogic C3 peripherals clock controller" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_CLKC_UTILS + imply COMMON_CLK_SCMI + imply COMMON_CLK_C3_PLL + help + Support for the Peripherals clock controller on Amlogic C302X and + C308L devices, AKA C3. Say Y if you want the peripherals clock to + work. + +config COMMON_CLK_G12A + tristate "G12 and SM1 SoC clock controllers support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC + select COMMON_CLK_MESON_CPU_DYNDIV + select COMMON_CLK_MESON_VID_PLL_DIV + select COMMON_CLK_MESON_VCLK + select MFD_SYSCON + help + Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 + devices, aka g12a. Say Y if you want peripherals to work. + +config COMMON_CLK_S4_PLL + tristate "S4 SoC PLL clock controllers support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_REGMAP + help + Support for the PLL clock controller on Amlogic S805X2 and S905Y4 devices, + AKA S4. Say Y if you want the board to work, because PLLs are the parent of + most peripherals. + +config COMMON_CLK_S4_PERIPHERALS + tristate "S4 SoC peripherals clock controllers support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_VID_PLL_DIV + help + Support for the peripherals clock controller on Amlogic S805X2 and S905Y4 + devices, AKA S4. Say Y if you want S4 peripherals clock controller to work. + +config COMMON_CLK_T7_PLL + tristate "Amlogic T7 SoC PLL controller support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + imply COMMON_CLK_SCMI + help + Support for the PLL clock controller on Amlogic A311D2 based + device, AKA T7. PLLs are required by most peripheral to operate. + Say Y if you want T7 PLL clock controller to work. + +config COMMON_CLK_T7_PERIPHERALS + tristate "Amlogic T7 SoC peripherals clock controller support" + depends on ARM64 + default ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_CLKC_UTILS + select COMMON_CLK_MESON_DUALDIV + imply COMMON_CLK_SCMI + imply COMMON_CLK_T7_PLL + help + Support for the peripherals clock controller on Amlogic A311D2 based + device, AKA T7. Peripherals are required by most peripheral to operate. + Say Y if you want T7 peripherals clock controller to work. +endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile new file mode 100644 index 000000000..56b04254e --- /dev/null +++ b/drivers/clk/meson/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Amlogic clock drivers + +obj-$(CONFIG_COMMON_CLK_MESON_CLKC_UTILS) += meson-clkc-utils.o +obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o +obj-$(CONFIG_COMMON_CLK_MESON_CPU_DYNDIV) += clk-cpu-dyndiv.o +obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o +obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o +obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o +obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o +obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o +obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o +obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o +obj-$(CONFIG_COMMON_CLK_MESON_VCLK) += vclk.o + +# Amlogic Clock controllers + +obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o +obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o +obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o +obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o +obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o +obj-$(CONFIG_COMMON_CLK_A9_AO) += a9-aoclk.o +obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o +obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o +obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o +obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o +obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o +obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o +obj-$(CONFIG_COMMON_CLK_T7_PLL) += t7-pll.o +obj-$(CONFIG_COMMON_CLK_T7_PERIPHERALS) += t7-peripherals.o diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c new file mode 100644 index 000000000..43cd6281b --- /dev/null +++ b/drivers/clk/meson/a1-peripherals.c @@ -0,0 +1,2099 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + * + * Copyright (c) 2023, SberDevices. All Rights Reserved. + * Author: Dmitry Rokosov + */ + +#include +#include +#include "clk-dualdiv.h" +#include "clk-regmap.h" +#include "meson-clkc-utils.h" + +#include + +#define SYS_OSCIN_CTRL 0x0 +#define RTC_BY_OSCIN_CTRL0 0x4 +#define RTC_BY_OSCIN_CTRL1 0x8 +#define RTC_CTRL 0xc +#define SYS_CLK_CTRL0 0x10 +#define SYS_CLK_EN0 0x1c +#define SYS_CLK_EN1 0x20 +#define AXI_CLK_EN 0x24 +#define DSPA_CLK_EN 0x28 +#define DSPB_CLK_EN 0x2c +#define DSPA_CLK_CTRL0 0x30 +#define DSPB_CLK_CTRL0 0x34 +#define CLK12_24_CTRL 0x38 +#define GEN_CLK_CTRL 0x3c +#define SAR_ADC_CLK_CTRL 0xc0 +#define PWM_CLK_AB_CTRL 0xc4 +#define PWM_CLK_CD_CTRL 0xc8 +#define PWM_CLK_EF_CTRL 0xcc +#define SPICC_CLK_CTRL 0xd0 +#define TS_CLK_CTRL 0xd4 +#define SPIFC_CLK_CTRL 0xd8 +#define USB_BUSCLK_CTRL 0xdc +#define SD_EMMC_CLK_CTRL 0xe0 +#define CECA_CLK_CTRL0 0xe4 +#define CECA_CLK_CTRL1 0xe8 +#define CECB_CLK_CTRL0 0xec +#define CECB_CLK_CTRL1 0xf0 +#define PSRAM_CLK_CTRL 0xf4 +#define DMC_CLK_CTRL 0xf8 + +static struct clk_regmap a1_xtal_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "xtal_in", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fixpll_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "fixpll_in", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_usb_phy_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_phy_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_usb_ctrl_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_ctrl_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_hifipll_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "hifipll_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_syspll_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "syspll_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_dds_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_OSCIN_CTRL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data) { + .name = "dds_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_rtc_32k_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param a1_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, + {} +}; + +static struct clk_regmap a1_rtc_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a1_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_rtc_32k_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_rtc_32k_xtal = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_xtal", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_rtc_32k_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_rtc_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_CTRL, + .mask = 0x3, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_rtc_32k_xtal.hw, + &a1_rtc_32k_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_rtc = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_rtc_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 a1_sys_parents_val_table[] = { 0, 1, 2, 3, 7 }; +static const struct clk_parent_data a1_sys_parents[] = { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div2" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div5" }, + { .hw = &a1_rtc.hw }, +}; + +static struct clk_regmap a1_sys_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 26, + .table = a1_sys_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_b_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = a1_sys_parents, + .num_parents = ARRAY_SIZE(a1_sys_parents), + }, +}; + +static struct clk_regmap a1_sys_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SYS_CLK_CTRL0, + .shift = 16, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_b_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sys_b_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sys_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_CLK_CTRL0, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data) { + .name = "sys_b", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sys_b_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sys_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 10, + .table = a1_sys_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_a_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = a1_sys_parents, + .num_parents = ARRAY_SIZE(a1_sys_parents), + }, +}; + +static struct clk_regmap a1_sys_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SYS_CLK_CTRL0, + .shift = 0, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_a_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sys_a_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sys_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = SYS_CLK_CTRL0, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "sys_a", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sys_a_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sys = { + .data = &(struct clk_regmap_mux_data){ + .offset = SYS_CLK_CTRL0, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sys_a.hw, + &a1_sys_b.hw, + }, + .num_parents = 2, + /* + * This clock is used by APB bus which is set in boot ROM code + * and is required by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + }, +}; + +static u32 a1_dsp_parents_val_table[] = { 0, 1, 2, 3, 4, 7 }; +static const struct clk_parent_data a1_dsp_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "hifi_pll", }, + { .hw = &a1_rtc.hw }, +}; + +static struct clk_regmap a1_dspa_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPA_CLK_CTRL0, + .mask = 0x7, + .shift = 10, + .table = a1_dsp_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa_a_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), + }, +}; + +static struct clk_regmap a1_dspa_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = DSPA_CLK_CTRL0, + .shift = 0, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa_a_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_a_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPA_CLK_CTRL0, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspa_a", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_a_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPA_CLK_CTRL0, + .mask = 0x7, + .shift = 26, + .table = a1_dsp_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa_b_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), + }, +}; + +static struct clk_regmap a1_dspa_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = DSPA_CLK_CTRL0, + .shift = 16, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa_b_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_b_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPA_CLK_CTRL0, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspa_b", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_b_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPA_CLK_CTRL0, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_a.hw, + &a1_dspa_b.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPA_CLK_EN, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspa_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspa_en_nic = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPA_CLK_EN, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspa_en_nic", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspa_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPB_CLK_CTRL0, + .mask = 0x7, + .shift = 10, + .table = a1_dsp_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb_a_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), + }, +}; + +static struct clk_regmap a1_dspb_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = DSPB_CLK_CTRL0, + .shift = 0, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb_a_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_a_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPB_CLK_CTRL0, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspb_a", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_a_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPB_CLK_CTRL0, + .mask = 0x7, + .shift = 26, + .table = a1_dsp_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb_b_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_dsp_parents, + .num_parents = ARRAY_SIZE(a1_dsp_parents), + }, +}; + +static struct clk_regmap a1_dspb_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = DSPB_CLK_CTRL0, + .shift = 16, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb_b_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_b_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPB_CLK_CTRL0, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspb_b", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_b_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPB_CLK_CTRL0, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_a.hw, + &a1_dspb_b.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPB_CLK_EN, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspb_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dspb_en_nic = { + .data = &(struct clk_regmap_gate_data){ + .offset = DSPB_CLK_EN, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "dspb_en_nic", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dspb_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_24m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "24m", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor a1_24m_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "24m_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_24m.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_12m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "12m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_24m_div2.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div2_divn_pre = { + .data = &(struct clk_regmap_div_data){ + .offset = CLK12_24_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_divn_pre", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fclk_div2", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div2_divn = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_divn", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fclk_div2_divn_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * the index 2 is sys_pll_div16, it will be implemented in the CPU clock driver, + * the index 4 is the clock measurement source, it's not supported yet + */ +static u32 a1_gen_parents_val_table[] = { 0, 1, 3, 5, 6, 7, 8 }; +static const struct clk_parent_data a1_gen_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a1_rtc.hw }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, +}; + +static struct clk_regmap a1_gen_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = GEN_CLK_CTRL, + .mask = 0xf, + .shift = 12, + .table = a1_gen_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_gen_parents, + .num_parents = ARRAY_SIZE(a1_gen_parents), + /* + * The GEN clock can be connected to an external pad, so it + * may be set up directly from the device tree. Additionally, + * the GEN clock can be inherited from a more accurate RTC + * clock, so in certain situations, it may be necessary + * to freeze its parent. + */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap a1_gen_div = { + .data = &(struct clk_regmap_div_data){ + .offset = GEN_CLK_CTRL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_gen_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_gen = { + .data = &(struct clk_regmap_gate_data){ + .offset = GEN_CLK_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_gen_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_saradc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SAR_ADC_CLK_CTRL, + .mask = 0x1, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &a1_sys.hw, }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap a1_saradc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SAR_ADC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_saradc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_saradc = { + .data = &(struct clk_regmap_gate_data){ + .offset = SAR_ADC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "saradc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_saradc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a1_pwm_abcd_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a1_sys.hw }, + { .hw = &a1_rtc.hw }, +}; + +static struct clk_regmap a1_pwm_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_AB_CTRL, + .mask = 0x1, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_a_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), + }, +}; + +static struct clk_regmap a1_pwm_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_AB_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_a_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_a_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_AB_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_a", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_a_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_AB_CTRL, + .mask = 0x1, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_b_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), + }, +}; + +static struct clk_regmap a1_pwm_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_AB_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_b_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_b_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_AB_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_b", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_b_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_c_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_CD_CTRL, + .mask = 0x1, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_c_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), + }, +}; + +static struct clk_regmap a1_pwm_c_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_CD_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_c_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_c_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_c = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_CD_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_c", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_c_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_d_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_CD_CTRL, + .mask = 0x1, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_d_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_abcd_parents, + .num_parents = ARRAY_SIZE(a1_pwm_abcd_parents), + }, +}; + +static struct clk_regmap a1_pwm_d_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_CD_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_d_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_d_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_d = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_CD_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_d", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_d_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a1_pwm_ef_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a1_sys.hw }, + { .fw_name = "fclk_div5", }, + { .hw = &a1_rtc.hw }, +}; + +static struct clk_regmap a1_pwm_e_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_EF_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_e_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_ef_parents, + .num_parents = ARRAY_SIZE(a1_pwm_ef_parents), + }, +}; + +static struct clk_regmap a1_pwm_e_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_EF_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_e_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_e_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_e = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_EF_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_e", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_e_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_f_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PWM_CLK_EF_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_f_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_pwm_ef_parents, + .num_parents = ARRAY_SIZE(a1_pwm_ef_parents), + }, +}; + +static struct clk_regmap a1_pwm_f_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PWM_CLK_EF_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_f_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_f_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_pwm_f = { + .data = &(struct clk_regmap_gate_data){ + .offset = PWM_CLK_EF_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "pwm_f", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_pwm_f_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * spicc clk + * fdiv2 |\ |\ _____ + * ---------| |---DIV--| | | | spicc out + * ---------| | | |-----|GATE |--------- + * ..... |/ | / |_____| + * --------------------|/ + * 24M + */ +static const struct clk_parent_data a1_spi_parents[] = { + { .fw_name = "fclk_div2"}, + { .fw_name = "fclk_div3"}, + { .fw_name = "fclk_div5"}, + { .fw_name = "hifi_pll" }, +}; + +static struct clk_regmap a1_spicc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SPICC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_spi_parents, + .num_parents = ARRAY_SIZE(a1_spi_parents), + }, +}; + +static struct clk_regmap a1_spicc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SPICC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_spicc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_spicc_sel2 = { + .data = &(struct clk_regmap_mux_data){ + .offset = SPICC_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc_sel2", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a1_spicc_div.hw }, + { .fw_name = "xtal", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_spicc = { + .data = &(struct clk_regmap_gate_data){ + .offset = SPICC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "spicc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_spicc_sel2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_ts_div = { + .data = &(struct clk_regmap_div_data){ + .offset = TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_ts = { + .data = &(struct clk_regmap_gate_data){ + .offset = TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_ts_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_spifc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SPIFC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "spifc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_spi_parents, + .num_parents = ARRAY_SIZE(a1_spi_parents), + }, +}; + +static struct clk_regmap a1_spifc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SPIFC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "spifc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_spifc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_spifc_sel2 = { + .data = &(struct clk_regmap_mux_data){ + .offset = SPIFC_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "spifc_sel2", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a1_spifc_div.hw }, + { .fw_name = "xtal", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_spifc = { + .data = &(struct clk_regmap_gate_data){ + .offset = SPIFC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "spifc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_spifc_sel2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a1_usb_bus_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a1_sys.hw }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, +}; + +static struct clk_regmap a1_usb_bus_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = USB_BUSCLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "usb_bus_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_usb_bus_parents, + .num_parents = ARRAY_SIZE(a1_usb_bus_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_usb_bus_div = { + .data = &(struct clk_regmap_div_data){ + .offset = USB_BUSCLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "usb_bus_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_usb_bus_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_usb_bus = { + .data = &(struct clk_regmap_gate_data){ + .offset = USB_BUSCLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_bus", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_usb_bus_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a1_sd_emmc_parents[] = { + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "hifi_pll", }, +}; + +static struct clk_regmap a1_sd_emmc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = SD_EMMC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), + }, +}; + +static struct clk_regmap a1_sd_emmc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = SD_EMMC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sd_emmc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sd_emmc_sel2 = { + .data = &(struct clk_regmap_mux_data){ + .offset = SD_EMMC_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_sel2", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a1_sd_emmc_div.hw }, + { .fw_name = "xtal", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_sd_emmc = { + .data = &(struct clk_regmap_gate_data){ + .offset = SD_EMMC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_sd_emmc_sel2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_psram_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = PSRAM_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "psram_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), + }, +}; + +static struct clk_regmap a1_psram_div = { + .data = &(struct clk_regmap_div_data){ + .offset = PSRAM_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "psram_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_psram_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_psram_sel2 = { + .data = &(struct clk_regmap_mux_data){ + .offset = PSRAM_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "psram_sel2", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a1_psram_div.hw }, + { .fw_name = "xtal", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_psram = { + .data = &(struct clk_regmap_gate_data){ + .offset = PSRAM_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "psram", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_psram_sel2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dmc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = DMC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "dmc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a1_sd_emmc_parents, + .num_parents = ARRAY_SIZE(a1_sd_emmc_parents), + }, +}; + +static struct clk_regmap a1_dmc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = DMC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "dmc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dmc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dmc_sel2 = { + .data = &(struct clk_regmap_mux_data){ + .offset = DMC_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dmc_sel2", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a1_dmc_div.hw }, + { .fw_name = "xtal", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_dmc = { + .data = &(struct clk_regmap_gate_data){ + .offset = DMC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "dmc", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_dmc_sel2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_ceca_32k_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CLK_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ceca_32k_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_ceca_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECA_CLK_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECA_CLK_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECA_CLK_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECA_CLK_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECA_CLK_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a1_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_ceca_32k_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_ceca_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CLK_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_ceca_32k_div.hw, + &a1_ceca_32k_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_ceca_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CLK_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_ceca_32k_sel_pre.hw, + &a1_rtc.hw, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap a1_ceca_32k_out = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CLK_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_out", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_ceca_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_cecb_32k_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CLK_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "cecb_32k_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_cecb_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECB_CLK_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECB_CLK_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECB_CLK_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECB_CLK_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECB_CLK_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a1_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_cecb_32k_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_cecb_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CLK_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_cecb_32k_div.hw, + &a1_cecb_32k_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a1_cecb_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CLK_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_cecb_32k_sel_pre.hw, + &a1_rtc.hw, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap a1_cecb_32k_out = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CLK_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_out", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_cecb_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a1_pclk_parents = { .hw = &a1_sys.hw }; + +#define A1_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(a1_##_name, _reg, _bit, &a1_pclk_parents, _flags) + +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static A1_PCLK(clktree, SYS_CLK_EN0, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(reset_ctrl, SYS_CLK_EN0, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(analog_ctrl, SYS_CLK_EN0, 2, CLK_IGNORE_UNUSED); +static A1_PCLK(pwr_ctrl, SYS_CLK_EN0, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(pad_ctrl, SYS_CLK_EN0, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_ctrl, SYS_CLK_EN0, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(temp_sensor, SYS_CLK_EN0, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(am2axi_dev, SYS_CLK_EN0, 7, CLK_IGNORE_UNUSED); +static A1_PCLK(spicc_b, SYS_CLK_EN0, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(spicc_a, SYS_CLK_EN0, 9, CLK_IGNORE_UNUSED); +static A1_PCLK(msr, SYS_CLK_EN0, 10, CLK_IGNORE_UNUSED); +static A1_PCLK(audio, SYS_CLK_EN0, 11, CLK_IGNORE_UNUSED); +static A1_PCLK(jtag_ctrl, SYS_CLK_EN0, 12, CLK_IGNORE_UNUSED); +static A1_PCLK(saradc_en, SYS_CLK_EN0, 13, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_ef, SYS_CLK_EN0, 14, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_cd, SYS_CLK_EN0, 15, CLK_IGNORE_UNUSED); +static A1_PCLK(pwm_ab, SYS_CLK_EN0, 16, CLK_IGNORE_UNUSED); +static A1_PCLK(cec, SYS_CLK_EN0, 17, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_s, SYS_CLK_EN0, 18, CLK_IGNORE_UNUSED); +static A1_PCLK(ir_ctrl, SYS_CLK_EN0, 19, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_d, SYS_CLK_EN0, 20, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_c, SYS_CLK_EN0, 21, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_b, SYS_CLK_EN0, 22, CLK_IGNORE_UNUSED); +static A1_PCLK(i2c_m_a, SYS_CLK_EN0, 23, CLK_IGNORE_UNUSED); +static A1_PCLK(acodec, SYS_CLK_EN0, 24, CLK_IGNORE_UNUSED); +static A1_PCLK(otp, SYS_CLK_EN0, 25, CLK_IGNORE_UNUSED); +static A1_PCLK(sd_emmc_a, SYS_CLK_EN0, 26, CLK_IGNORE_UNUSED); +static A1_PCLK(usb_phy, SYS_CLK_EN0, 27, CLK_IGNORE_UNUSED); +static A1_PCLK(usb_ctrl, SYS_CLK_EN0, 28, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_dspb, SYS_CLK_EN0, 29, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_dspa, SYS_CLK_EN0, 30, CLK_IGNORE_UNUSED); +static A1_PCLK(dma, SYS_CLK_EN0, 31, CLK_IGNORE_UNUSED); + +static A1_PCLK(irq_ctrl, SYS_CLK_EN1, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(nic, SYS_CLK_EN1, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(gic, SYS_CLK_EN1, 2, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_c, SYS_CLK_EN1, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_b, SYS_CLK_EN1, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(uart_a, SYS_CLK_EN1, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(sys_psram, SYS_CLK_EN1, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(rsa, SYS_CLK_EN1, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(coresight, SYS_CLK_EN1, 9, CLK_IGNORE_UNUSED); + +static A1_PCLK(am2axi_vad, AXI_CLK_EN, 0, CLK_IGNORE_UNUSED); +static A1_PCLK(audio_vad, AXI_CLK_EN, 1, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_dmc, AXI_CLK_EN, 3, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_psram, AXI_CLK_EN, 4, CLK_IGNORE_UNUSED); +static A1_PCLK(ramb, AXI_CLK_EN, 5, CLK_IGNORE_UNUSED); +static A1_PCLK(rama, AXI_CLK_EN, 6, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_spifc, AXI_CLK_EN, 7, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_nic, AXI_CLK_EN, 8, CLK_IGNORE_UNUSED); +static A1_PCLK(axi_dma, AXI_CLK_EN, 9, CLK_IGNORE_UNUSED); +static A1_PCLK(cpu_ctrl, AXI_CLK_EN, 10, CLK_IGNORE_UNUSED); +static A1_PCLK(rom, AXI_CLK_EN, 11, CLK_IGNORE_UNUSED); +static A1_PCLK(prod_i2c, AXI_CLK_EN, 12, CLK_IGNORE_UNUSED); + +/* Array of all clocks registered by this provider */ +static struct clk_hw *a1_peripherals_hw_clks[] = { + [CLKID_XTAL_IN] = &a1_xtal_in.hw, + [CLKID_FIXPLL_IN] = &a1_fixpll_in.hw, + [CLKID_USB_PHY_IN] = &a1_usb_phy_in.hw, + [CLKID_USB_CTRL_IN] = &a1_usb_ctrl_in.hw, + [CLKID_HIFIPLL_IN] = &a1_hifipll_in.hw, + [CLKID_SYSPLL_IN] = &a1_syspll_in.hw, + [CLKID_DDS_IN] = &a1_dds_in.hw, + [CLKID_SYS] = &a1_sys.hw, + [CLKID_CLKTREE] = &a1_clktree.hw, + [CLKID_RESET_CTRL] = &a1_reset_ctrl.hw, + [CLKID_ANALOG_CTRL] = &a1_analog_ctrl.hw, + [CLKID_PWR_CTRL] = &a1_pwr_ctrl.hw, + [CLKID_PAD_CTRL] = &a1_pad_ctrl.hw, + [CLKID_SYS_CTRL] = &a1_sys_ctrl.hw, + [CLKID_TEMP_SENSOR] = &a1_temp_sensor.hw, + [CLKID_AM2AXI_DIV] = &a1_am2axi_dev.hw, + [CLKID_SPICC_B] = &a1_spicc_b.hw, + [CLKID_SPICC_A] = &a1_spicc_a.hw, + [CLKID_MSR] = &a1_msr.hw, + [CLKID_AUDIO] = &a1_audio.hw, + [CLKID_JTAG_CTRL] = &a1_jtag_ctrl.hw, + [CLKID_SARADC_EN] = &a1_saradc_en.hw, + [CLKID_PWM_EF] = &a1_pwm_ef.hw, + [CLKID_PWM_CD] = &a1_pwm_cd.hw, + [CLKID_PWM_AB] = &a1_pwm_ab.hw, + [CLKID_CEC] = &a1_cec.hw, + [CLKID_I2C_S] = &a1_i2c_s.hw, + [CLKID_IR_CTRL] = &a1_ir_ctrl.hw, + [CLKID_I2C_M_D] = &a1_i2c_m_d.hw, + [CLKID_I2C_M_C] = &a1_i2c_m_c.hw, + [CLKID_I2C_M_B] = &a1_i2c_m_b.hw, + [CLKID_I2C_M_A] = &a1_i2c_m_a.hw, + [CLKID_ACODEC] = &a1_acodec.hw, + [CLKID_OTP] = &a1_otp.hw, + [CLKID_SD_EMMC_A] = &a1_sd_emmc_a.hw, + [CLKID_USB_PHY] = &a1_usb_phy.hw, + [CLKID_USB_CTRL] = &a1_usb_ctrl.hw, + [CLKID_SYS_DSPB] = &a1_sys_dspb.hw, + [CLKID_SYS_DSPA] = &a1_sys_dspa.hw, + [CLKID_DMA] = &a1_dma.hw, + [CLKID_IRQ_CTRL] = &a1_irq_ctrl.hw, + [CLKID_NIC] = &a1_nic.hw, + [CLKID_GIC] = &a1_gic.hw, + [CLKID_UART_C] = &a1_uart_c.hw, + [CLKID_UART_B] = &a1_uart_b.hw, + [CLKID_UART_A] = &a1_uart_a.hw, + [CLKID_SYS_PSRAM] = &a1_sys_psram.hw, + [CLKID_RSA] = &a1_rsa.hw, + [CLKID_CORESIGHT] = &a1_coresight.hw, + [CLKID_AM2AXI_VAD] = &a1_am2axi_vad.hw, + [CLKID_AUDIO_VAD] = &a1_audio_vad.hw, + [CLKID_AXI_DMC] = &a1_axi_dmc.hw, + [CLKID_AXI_PSRAM] = &a1_axi_psram.hw, + [CLKID_RAMB] = &a1_ramb.hw, + [CLKID_RAMA] = &a1_rama.hw, + [CLKID_AXI_SPIFC] = &a1_axi_spifc.hw, + [CLKID_AXI_NIC] = &a1_axi_nic.hw, + [CLKID_AXI_DMA] = &a1_axi_dma.hw, + [CLKID_CPU_CTRL] = &a1_cpu_ctrl.hw, + [CLKID_ROM] = &a1_rom.hw, + [CLKID_PROC_I2C] = &a1_prod_i2c.hw, + [CLKID_DSPA_SEL] = &a1_dspa_sel.hw, + [CLKID_DSPB_SEL] = &a1_dspb_sel.hw, + [CLKID_DSPA_EN] = &a1_dspa_en.hw, + [CLKID_DSPA_EN_NIC] = &a1_dspa_en_nic.hw, + [CLKID_DSPB_EN] = &a1_dspb_en.hw, + [CLKID_DSPB_EN_NIC] = &a1_dspb_en_nic.hw, + [CLKID_RTC] = &a1_rtc.hw, + [CLKID_CECA_32K] = &a1_ceca_32k_out.hw, + [CLKID_CECB_32K] = &a1_cecb_32k_out.hw, + [CLKID_24M] = &a1_24m.hw, + [CLKID_12M] = &a1_12m.hw, + [CLKID_FCLK_DIV2_DIVN] = &a1_fclk_div2_divn.hw, + [CLKID_GEN] = &a1_gen.hw, + [CLKID_SARADC_SEL] = &a1_saradc_sel.hw, + [CLKID_SARADC] = &a1_saradc.hw, + [CLKID_PWM_A] = &a1_pwm_a.hw, + [CLKID_PWM_B] = &a1_pwm_b.hw, + [CLKID_PWM_C] = &a1_pwm_c.hw, + [CLKID_PWM_D] = &a1_pwm_d.hw, + [CLKID_PWM_E] = &a1_pwm_e.hw, + [CLKID_PWM_F] = &a1_pwm_f.hw, + [CLKID_SPICC] = &a1_spicc.hw, + [CLKID_TS] = &a1_ts.hw, + [CLKID_SPIFC] = &a1_spifc.hw, + [CLKID_USB_BUS] = &a1_usb_bus.hw, + [CLKID_SD_EMMC] = &a1_sd_emmc.hw, + [CLKID_PSRAM] = &a1_psram.hw, + [CLKID_DMC] = &a1_dmc.hw, + [CLKID_SYS_A_SEL] = &a1_sys_a_sel.hw, + [CLKID_SYS_A_DIV] = &a1_sys_a_div.hw, + [CLKID_SYS_A] = &a1_sys_a.hw, + [CLKID_SYS_B_SEL] = &a1_sys_b_sel.hw, + [CLKID_SYS_B_DIV] = &a1_sys_b_div.hw, + [CLKID_SYS_B] = &a1_sys_b.hw, + [CLKID_DSPA_A_SEL] = &a1_dspa_a_sel.hw, + [CLKID_DSPA_A_DIV] = &a1_dspa_a_div.hw, + [CLKID_DSPA_A] = &a1_dspa_a.hw, + [CLKID_DSPA_B_SEL] = &a1_dspa_b_sel.hw, + [CLKID_DSPA_B_DIV] = &a1_dspa_b_div.hw, + [CLKID_DSPA_B] = &a1_dspa_b.hw, + [CLKID_DSPB_A_SEL] = &a1_dspb_a_sel.hw, + [CLKID_DSPB_A_DIV] = &a1_dspb_a_div.hw, + [CLKID_DSPB_A] = &a1_dspb_a.hw, + [CLKID_DSPB_B_SEL] = &a1_dspb_b_sel.hw, + [CLKID_DSPB_B_DIV] = &a1_dspb_b_div.hw, + [CLKID_DSPB_B] = &a1_dspb_b.hw, + [CLKID_RTC_32K_IN] = &a1_rtc_32k_in.hw, + [CLKID_RTC_32K_DIV] = &a1_rtc_32k_div.hw, + [CLKID_RTC_32K_XTAL] = &a1_rtc_32k_xtal.hw, + [CLKID_RTC_32K_SEL] = &a1_rtc_32k_sel.hw, + [CLKID_CECB_32K_IN] = &a1_cecb_32k_in.hw, + [CLKID_CECB_32K_DIV] = &a1_cecb_32k_div.hw, + [CLKID_CECB_32K_SEL_PRE] = &a1_cecb_32k_sel_pre.hw, + [CLKID_CECB_32K_SEL] = &a1_cecb_32k_sel.hw, + [CLKID_CECA_32K_IN] = &a1_ceca_32k_in.hw, + [CLKID_CECA_32K_DIV] = &a1_ceca_32k_div.hw, + [CLKID_CECA_32K_SEL_PRE] = &a1_ceca_32k_sel_pre.hw, + [CLKID_CECA_32K_SEL] = &a1_ceca_32k_sel.hw, + [CLKID_DIV2_PRE] = &a1_fclk_div2_divn_pre.hw, + [CLKID_24M_DIV2] = &a1_24m_div2.hw, + [CLKID_GEN_SEL] = &a1_gen_sel.hw, + [CLKID_GEN_DIV] = &a1_gen_div.hw, + [CLKID_SARADC_DIV] = &a1_saradc_div.hw, + [CLKID_PWM_A_SEL] = &a1_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &a1_pwm_a_div.hw, + [CLKID_PWM_B_SEL] = &a1_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &a1_pwm_b_div.hw, + [CLKID_PWM_C_SEL] = &a1_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &a1_pwm_c_div.hw, + [CLKID_PWM_D_SEL] = &a1_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &a1_pwm_d_div.hw, + [CLKID_PWM_E_SEL] = &a1_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &a1_pwm_e_div.hw, + [CLKID_PWM_F_SEL] = &a1_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &a1_pwm_f_div.hw, + [CLKID_SPICC_SEL] = &a1_spicc_sel.hw, + [CLKID_SPICC_DIV] = &a1_spicc_div.hw, + [CLKID_SPICC_SEL2] = &a1_spicc_sel2.hw, + [CLKID_TS_DIV] = &a1_ts_div.hw, + [CLKID_SPIFC_SEL] = &a1_spifc_sel.hw, + [CLKID_SPIFC_DIV] = &a1_spifc_div.hw, + [CLKID_SPIFC_SEL2] = &a1_spifc_sel2.hw, + [CLKID_USB_BUS_SEL] = &a1_usb_bus_sel.hw, + [CLKID_USB_BUS_DIV] = &a1_usb_bus_div.hw, + [CLKID_SD_EMMC_SEL] = &a1_sd_emmc_sel.hw, + [CLKID_SD_EMMC_DIV] = &a1_sd_emmc_div.hw, + [CLKID_SD_EMMC_SEL2] = &a1_sd_emmc_sel2.hw, + [CLKID_PSRAM_SEL] = &a1_psram_sel.hw, + [CLKID_PSRAM_DIV] = &a1_psram_div.hw, + [CLKID_PSRAM_SEL2] = &a1_psram_sel2.hw, + [CLKID_DMC_SEL] = &a1_dmc_sel.hw, + [CLKID_DMC_DIV] = &a1_dmc_div.hw, + [CLKID_DMC_SEL2] = &a1_dmc_sel2.hw, +}; + +static const struct meson_clkc_data a1_peripherals_clkc_data = { + .hw_clks = { + .hws = a1_peripherals_hw_clks, + .num = ARRAY_SIZE(a1_peripherals_hw_clks), + }, +}; + +static const struct of_device_id a1_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,a1-peripherals-clkc", + .data = &a1_peripherals_clkc_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, a1_peripherals_clkc_match_table); + +static struct platform_driver a1_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "a1-peripherals-clkc", + .of_match_table = a1_peripherals_clkc_match_table, + }, +}; +module_platform_driver(a1_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic A1 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_AUTHOR("Dmitry Rokosov "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c new file mode 100644 index 000000000..100c42212 --- /dev/null +++ b/drivers/clk/meson/a1-pll.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + * + * Copyright (c) 2023, SberDevices. All Rights Reserved. + * Author: Dmitry Rokosov + */ + +#include +#include +#include "clk-pll.h" +#include "clk-regmap.h" +#include "meson-clkc-utils.h" + +#define ANACTRL_FIXPLL_CTRL0 0x0 +#define ANACTRL_FIXPLL_CTRL1 0x4 +#define ANACTRL_FIXPLL_STS 0x14 +#define ANACTRL_HIFIPLL_CTRL0 0xc0 +#define ANACTRL_HIFIPLL_CTRL1 0xc4 +#define ANACTRL_HIFIPLL_CTRL2 0xc8 +#define ANACTRL_HIFIPLL_CTRL3 0xcc +#define ANACTRL_HIFIPLL_CTRL4 0xd0 +#define ANACTRL_HIFIPLL_STS 0xd4 + +#include + +static struct clk_regmap a1_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = ANACTRL_FIXPLL_CTRL1, + .shift = 0, + .width = 19, + }, + .l = { + .reg_off = ANACTRL_FIXPLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fixpll_in", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fixed_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "fixed_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static const struct pll_mult_range a1_hifi_pll_range = { + .min = 32, + .max = 64, +}; + +static const struct reg_sequence a1_hifi_pll_init_regs[] = { + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 }, + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 }, + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 }, + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 }, + { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18000 }, +}; + +static struct clk_regmap a1_hifi_pll = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = ANACTRL_HIFIPLL_CTRL1, + .shift = 0, + .width = 19, + }, + .l = { + .reg_off = ANACTRL_HIFIPLL_STS, + .shift = 31, + .width = 1, + }, + .current_en = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 26, + .width = 1, + }, + .l_detect = { + .reg_off = ANACTRL_HIFIPLL_CTRL2, + .shift = 6, + .width = 1, + }, + .range = &a1_hifi_pll_range, + .init_regs = a1_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(a1_hifi_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "hifipll_in", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor a1_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fclk_div2_div.hw + }, + .num_parents = 1, + /* + * This clock is used by DDR clock in BL2 firmware + * and is required by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor a1_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fclk_div3_div.hw + }, + .num_parents = 1, + /* + * This clock is used by APB bus which is set in boot ROM code + * and is required by the platform to operate correctly. + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor a1_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fclk_div5_div.hw + }, + .num_parents = 1, + /* + * This clock is used by AXI bus which setted in Romcode + * and is required by the platform to operate correctly. + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor a1_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a1_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a1_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +/* Array of all clocks registered by this provider */ +static struct clk_hw *a1_pll_hw_clks[] = { + [CLKID_FIXED_PLL_DCO] = &a1_fixed_pll_dco.hw, + [CLKID_FIXED_PLL] = &a1_fixed_pll.hw, + [CLKID_FCLK_DIV2_DIV] = &a1_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &a1_fclk_div3_div.hw, + [CLKID_FCLK_DIV5_DIV] = &a1_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &a1_fclk_div7_div.hw, + [CLKID_FCLK_DIV2] = &a1_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &a1_fclk_div3.hw, + [CLKID_FCLK_DIV5] = &a1_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &a1_fclk_div7.hw, + [CLKID_HIFI_PLL] = &a1_hifi_pll.hw, +}; + +static const struct meson_clkc_data a1_pll_clkc_data = { + .hw_clks = { + .hws = a1_pll_hw_clks, + .num = ARRAY_SIZE(a1_pll_hw_clks), + }, +}; + +static const struct of_device_id a1_pll_clkc_match_table[] = { + { + .compatible = "amlogic,a1-pll-clkc", + .data = &a1_pll_clkc_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, a1_pll_clkc_match_table); + +static struct platform_driver a1_pll_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "a1-pll-clkc", + .of_match_table = a1_pll_clkc_match_table, + }, +}; +module_platform_driver(a1_pll_clkc_driver); + +MODULE_DESCRIPTION("Amlogic A1 PLL Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_AUTHOR("Dmitry Rokosov "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/a9-aoclk.c b/drivers/clk/meson/a9-aoclk.c new file mode 100644 index 000000000..c82d4b1b5 --- /dev/null +++ b/drivers/clk/meson/a9-aoclk.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2026 Amlogic, Inc. All rights reserved + */ + +#include +#include +#include +#include +#include "clk-regmap.h" +#include "clk-dualdiv.h" +#include "meson-clkc-utils.h" + +#define AO_OSCIN_CTRL 0x00 +#define AO_SYS_CLK0 0x04 +#define AO_PWM_CLK_A_CTRL 0x1c +#define AO_PWM_CLK_B_CTRL 0x20 +#define AO_PWM_CLK_C_CTRL 0x24 +#define AO_PWM_CLK_D_CTRL 0x28 +#define AO_PWM_CLK_E_CTRL 0x2c +#define AO_PWM_CLK_F_CTRL 0x30 +#define AO_PWM_CLK_G_CTRL 0x34 +#define AO_CEC_CTRL0 0x38 +#define AO_CEC_CTRL1 0x3c +#define AO_RTC_BY_OSCIN_CTRL0 0x50 +#define AO_RTC_BY_OSCIN_CTRL1 0x54 + +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(a9_ao_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define A9_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(a9_ao_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define A9_COMP_GATE(_name, _reg, _bit) \ + MESON_COMP_GATE(a9_ao_, _name, _reg, _bit, CLK_SET_RATE_PARENT) + +static struct clk_regmap a9_ao_xtal_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_OSCIN_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "ao_xtal_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_ao_xtal = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_OSCIN_CTRL, + .mask = 0x1, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_xtal", + .ops = &clk_regmap_mux_ops, + /* ext_32k is from external PAD, do not automatically reparent */ + .parent_data = (const struct clk_parent_data []) { + { .hw = &a9_ao_xtal_in.hw }, + { .fw_name = "ext_32k", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap a9_ao_sys = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_OSCIN_CTRL, + .mask = 0x1, + .shift = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_sys", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a9_ao_xtal.hw }, + { .fw_name = "sys", }, + }, + .num_parents = 2, + }, +}; + +static const struct clk_parent_data a9_ao_pclk_parents = { .hw = &a9_ao_sys.hw }; + +#define A9_AO_PCLK(_name, _bit, _flags) \ + MESON_PCLK(a9_ao_sys_##_name, AO_SYS_CLK0, _bit, \ + &a9_ao_pclk_parents, _flags) + +/* + * A9 integrates a low-power microprocessor (Always-on CPU: AOCPU). Some AO sys + * clocks control the AOCPU modules. Mark the AOCPU-related clocks with + * CLK_IS_CRITICAL to avoid them being disabled and impacting AOCPU functionality. + * AOCPU-related clocks list: + * - clktree + * - rst_ctrl + * - pad + * - irq + * - pwrctrl + * - aocpu + * - sram + */ +static A9_AO_PCLK(i3c, 0, 0); +static A9_AO_PCLK(rtc_reg, 1, 0); +static A9_AO_PCLK(clktree, 2, CLK_IS_CRITICAL); +static A9_AO_PCLK(rst_ctrl, 3, CLK_IS_CRITICAL); +static A9_AO_PCLK(pad, 4, CLK_IS_CRITICAL); +static A9_AO_PCLK(rtc_dig, 5, 0); +static A9_AO_PCLK(irq, 6, CLK_IS_CRITICAL); +static A9_AO_PCLK(pwrctrl, 7, CLK_IS_CRITICAL); +static A9_AO_PCLK(pwm_a, 8, 0); +static A9_AO_PCLK(pwm_b, 9, 0); +static A9_AO_PCLK(pwm_c, 10, 0); +static A9_AO_PCLK(pwm_d, 11, 0); +static A9_AO_PCLK(pwm_e, 12, 0); +static A9_AO_PCLK(pwm_f, 13, 0); +static A9_AO_PCLK(pwm_g, 14, 0); +static A9_AO_PCLK(i2c_a, 15, 0); +static A9_AO_PCLK(i2c_b, 16, 0); +static A9_AO_PCLK(i2c_c, 17, 0); +static A9_AO_PCLK(i2c_d, 18, 0); +static A9_AO_PCLK(sed, 19, 0); +static A9_AO_PCLK(ir_ctrl, 20, 0); +static A9_AO_PCLK(uart_b, 21, 0); +static A9_AO_PCLK(uart_c, 22, 0); +static A9_AO_PCLK(uart_d, 23, 0); +static A9_AO_PCLK(uart_e, 24, 0); +static A9_AO_PCLK(spisg_0, 25, 0); +static A9_AO_PCLK(rtc_secure, 26, 0); +static A9_AO_PCLK(cec, 27, 0); +static A9_AO_PCLK(aocpu, 28, CLK_IS_CRITICAL); +static A9_AO_PCLK(sram, 29, CLK_IS_CRITICAL); +static A9_AO_PCLK(spisg_1, 30, 0); +static A9_AO_PCLK(spisg_2, 31, 0); + +static const struct clk_parent_data a9_ao_pwm_parents[] = { + { .hw = &a9_ao_xtal.hw }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", } +}; + +static A9_COMP_SEL(pwm_a, AO_PWM_CLK_A_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_a, AO_PWM_CLK_A_CTRL, 0, 8); +static A9_COMP_GATE(pwm_a, AO_PWM_CLK_A_CTRL, 8); + +static A9_COMP_SEL(pwm_b, AO_PWM_CLK_B_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_b, AO_PWM_CLK_B_CTRL, 0, 8); +static A9_COMP_GATE(pwm_b, AO_PWM_CLK_B_CTRL, 8); + +static A9_COMP_SEL(pwm_c, AO_PWM_CLK_C_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_c, AO_PWM_CLK_C_CTRL, 0, 8); +static A9_COMP_GATE(pwm_c, AO_PWM_CLK_C_CTRL, 8); + +static A9_COMP_SEL(pwm_d, AO_PWM_CLK_D_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_d, AO_PWM_CLK_D_CTRL, 0, 8); +static A9_COMP_GATE(pwm_d, AO_PWM_CLK_D_CTRL, 8); + +static A9_COMP_SEL(pwm_e, AO_PWM_CLK_E_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_e, AO_PWM_CLK_E_CTRL, 0, 8); +static A9_COMP_GATE(pwm_e, AO_PWM_CLK_E_CTRL, 8); + +static A9_COMP_SEL(pwm_f, AO_PWM_CLK_F_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_f, AO_PWM_CLK_F_CTRL, 0, 8); +static A9_COMP_GATE(pwm_f, AO_PWM_CLK_F_CTRL, 8); + +static A9_COMP_SEL(pwm_g, AO_PWM_CLK_G_CTRL, 9, 0x7, a9_ao_pwm_parents); +static A9_COMP_DIV(pwm_g, AO_PWM_CLK_G_CTRL, 0, 8); +static A9_COMP_GATE(pwm_g, AO_PWM_CLK_G_CTRL, 8); + +static struct clk_regmap a9_ao_rtc_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ao_rtc_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_xtal.hw + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param a9_ao_dualdiv_table[] = { + { 733, 732, 8, 11, 1 }, + { /* sentinel */ } +}; + +static struct clk_regmap a9_ao_rtc_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a9_ao_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "a9_ao_rtc_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_rtc_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_ao_rtc_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_rtc_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_rtc_dualdiv_div.hw, + &a9_ao_rtc_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ao_rtc_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "ao_rtc_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_rtc_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ao_rtc = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_rtc", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_xtal.hw, + &a9_ao_rtc_dualdiv.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ao_cec_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ao_cec_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_xtal.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_ao_cec_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_CEC_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_CEC_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_CEC_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_CEC_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_CEC_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a9_ao_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_cec_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_ao_cec_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CEC_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_cec_dualdiv_div.hw, + &a9_ao_cec_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ao_cec_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_cec_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ao_cec = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CEC_CTRL1, + .mask = 0x1, + .shift = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ao_cec_dualdiv.hw, + &a9_ao_rtc.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_hw *a9_ao_hw_clks[] = { + [CLKID_AO_XTAL_IN] = &a9_ao_xtal_in.hw, + [CLKID_AO_XTAL] = &a9_ao_xtal.hw, + [CLKID_AO_SYS] = &a9_ao_sys.hw, + [CLKID_AO_SYS_I3C] = &a9_ao_sys_i3c.hw, + [CLKID_AO_SYS_RTC_REG] = &a9_ao_sys_rtc_reg.hw, + [CLKID_AO_SYS_CLKTREE] = &a9_ao_sys_clktree.hw, + [CLKID_AO_SYS_RST_CTRL] = &a9_ao_sys_rst_ctrl.hw, + [CLKID_AO_SYS_PAD] = &a9_ao_sys_pad.hw, + [CLKID_AO_SYS_RTC_DIG] = &a9_ao_sys_rtc_dig.hw, + [CLKID_AO_SYS_IRQ] = &a9_ao_sys_irq.hw, + [CLKID_AO_SYS_PWRCTRL] = &a9_ao_sys_pwrctrl.hw, + [CLKID_AO_SYS_PWM_A] = &a9_ao_sys_pwm_a.hw, + [CLKID_AO_SYS_PWM_B] = &a9_ao_sys_pwm_b.hw, + [CLKID_AO_SYS_PWM_C] = &a9_ao_sys_pwm_c.hw, + [CLKID_AO_SYS_PWM_D] = &a9_ao_sys_pwm_d.hw, + [CLKID_AO_SYS_PWM_E] = &a9_ao_sys_pwm_e.hw, + [CLKID_AO_SYS_PWM_F] = &a9_ao_sys_pwm_f.hw, + [CLKID_AO_SYS_PWM_G] = &a9_ao_sys_pwm_g.hw, + [CLKID_AO_SYS_I2C_A] = &a9_ao_sys_i2c_a.hw, + [CLKID_AO_SYS_I2C_B] = &a9_ao_sys_i2c_b.hw, + [CLKID_AO_SYS_I2C_C] = &a9_ao_sys_i2c_c.hw, + [CLKID_AO_SYS_I2C_D] = &a9_ao_sys_i2c_d.hw, + [CLKID_AO_SYS_SED] = &a9_ao_sys_sed.hw, + [CLKID_AO_SYS_IR_CTRL] = &a9_ao_sys_ir_ctrl.hw, + [CLKID_AO_SYS_UART_B] = &a9_ao_sys_uart_b.hw, + [CLKID_AO_SYS_UART_C] = &a9_ao_sys_uart_c.hw, + [CLKID_AO_SYS_UART_D] = &a9_ao_sys_uart_d.hw, + [CLKID_AO_SYS_UART_E] = &a9_ao_sys_uart_e.hw, + [CLKID_AO_SYS_SPISG_0] = &a9_ao_sys_spisg_0.hw, + [CLKID_AO_SYS_RTC_SECURE] = &a9_ao_sys_rtc_secure.hw, + [CLKID_AO_SYS_CEC] = &a9_ao_sys_cec.hw, + [CLKID_AO_SYS_AOCPU] = &a9_ao_sys_aocpu.hw, + [CLKID_AO_SYS_SRAM] = &a9_ao_sys_sram.hw, + [CLKID_AO_SYS_SPISG_1] = &a9_ao_sys_spisg_1.hw, + [CLKID_AO_SYS_SPISG_2] = &a9_ao_sys_spisg_2.hw, + [CLKID_AO_PWM_A_SEL] = &a9_ao_pwm_a_sel.hw, + [CLKID_AO_PWM_A_DIV] = &a9_ao_pwm_a_div.hw, + [CLKID_AO_PWM_A] = &a9_ao_pwm_a.hw, + [CLKID_AO_PWM_B_SEL] = &a9_ao_pwm_b_sel.hw, + [CLKID_AO_PWM_B_DIV] = &a9_ao_pwm_b_div.hw, + [CLKID_AO_PWM_B] = &a9_ao_pwm_b.hw, + [CLKID_AO_PWM_C_SEL] = &a9_ao_pwm_c_sel.hw, + [CLKID_AO_PWM_C_DIV] = &a9_ao_pwm_c_div.hw, + [CLKID_AO_PWM_C] = &a9_ao_pwm_c.hw, + [CLKID_AO_PWM_D_SEL] = &a9_ao_pwm_d_sel.hw, + [CLKID_AO_PWM_D_DIV] = &a9_ao_pwm_d_div.hw, + [CLKID_AO_PWM_D] = &a9_ao_pwm_d.hw, + [CLKID_AO_PWM_E_SEL] = &a9_ao_pwm_e_sel.hw, + [CLKID_AO_PWM_E_DIV] = &a9_ao_pwm_e_div.hw, + [CLKID_AO_PWM_E] = &a9_ao_pwm_e.hw, + [CLKID_AO_PWM_F_SEL] = &a9_ao_pwm_f_sel.hw, + [CLKID_AO_PWM_F_DIV] = &a9_ao_pwm_f_div.hw, + [CLKID_AO_PWM_F] = &a9_ao_pwm_f.hw, + [CLKID_AO_PWM_G_SEL] = &a9_ao_pwm_g_sel.hw, + [CLKID_AO_PWM_G_DIV] = &a9_ao_pwm_g_div.hw, + [CLKID_AO_PWM_G] = &a9_ao_pwm_g.hw, + [CLKID_AO_RTC_DUALDIV_IN] = &a9_ao_rtc_dualdiv_in.hw, + [CLKID_AO_RTC_DUALDIV_DIV] = &a9_ao_rtc_dualdiv_div.hw, + [CLKID_AO_RTC_DUALDIV_SEL] = &a9_ao_rtc_dualdiv_sel.hw, + [CLKID_AO_RTC_DUALDIV] = &a9_ao_rtc_dualdiv.hw, + [CLKID_AO_RTC] = &a9_ao_rtc.hw, + [CLKID_AO_CEC_DUALDIV_IN] = &a9_ao_cec_dualdiv_in.hw, + [CLKID_AO_CEC_DUALDIV_DIV] = &a9_ao_cec_dualdiv_div.hw, + [CLKID_AO_CEC_DUALDIV_SEL] = &a9_ao_cec_dualdiv_sel.hw, + [CLKID_AO_CEC_DUALDIV] = &a9_ao_cec_dualdiv.hw, + [CLKID_AO_CEC] = &a9_ao_cec.hw, +}; + +static const struct meson_clkc_data a9_ao_clkc_data = { + .hw_clks = { + .hws = a9_ao_hw_clks, + .num = ARRAY_SIZE(a9_ao_hw_clks), + }, +}; + +static const struct of_device_id a9_ao_clkc_match_table[] = { + { + .compatible = "amlogic,a9-aoclkc", + .data = &a9_ao_clkc_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, a9_ao_clkc_match_table); + +static struct platform_driver a9_ao_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "a9-aoclkc", + .of_match_table = a9_ao_clkc_match_table, + }, +}; +module_platform_driver(a9_ao_clkc_driver); + +MODULE_DESCRIPTION("Amlogic A9 Always-ON Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/a9-peripherals.c b/drivers/clk/meson/a9-peripherals.c new file mode 100644 index 000000000..b77e35f48 --- /dev/null +++ b/drivers/clk/meson/a9-peripherals.c @@ -0,0 +1,2089 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2026 Amlogic, Inc. All rights reserved + */ + +#include +#include +#include +#include +#include "clk-regmap.h" +#include "clk-dualdiv.h" +#include "meson-clkc-utils.h" +#include "vid-pll-div.h" + +#define SYS_CLK_EN0_REG0 0x30 +#define SYS_CLK_EN0_REG1 0x34 +#define SYS_CLK_EN0_REG2 0x38 +#define SYS_CLK_EN0_REG3 0x3c +#define SD_EMMC_CLK_CTRL0 0x90 +#define SD_EMMC_CLK_CTRL1 0x94 +#define PWM_CLK_H_CTRL 0xbc +#define PWM_CLK_I_CTRL 0xc0 +#define PWM_CLK_J_CTRL 0xc4 +#define PWM_CLK_K_CTRL 0xc8 +#define PWM_CLK_L_CTRL 0xcc +#define PWM_CLK_M_CTRL 0xd0 +#define PWM_CLK_N_CTRL 0xd4 +#define SPISG_CLK_CTRL 0x100 +#define SPISG_CLK_CTRL1 0x104 +#define SAR_CLK_CTRL 0x150 +#define AMFC_CLK_CTRL 0x154 +#define NNA_CLK_CTRL 0x15c +#define USB_CLK_CTRL 0x160 +#define PCIE_TL_CLK_CTRL 0x164 +#define CMPR_CLK_CTRL 0x168 +#define DEWARP_CLK_CTRL 0x16c +#define SC_CLK_CTRL 0x170 +#define DPTX_CLK_CTRL 0x178 +#define ISP_CLK_CTRL 0x17c +#define CVE_CLK_CTRL 0x180 +#define PP_CLK_CTRL 0x184 +#define GLB_CLK_CTRL 0x188 +#define USB_CLK_CTRL0 0x18c +#define USB_CLK_CTRL1 0x190 +#define CAN_CLK_CTRL 0x194 +#define CAN_CLK_CTRL1 0x198 +#define I3C_CLK_CTRL 0x19c +#define TS_CLK_CTRL 0x1a0 +#define ETH_CLK_CTRL 0x1a4 +#define GEN_CLK_CTRL 0x1a8 +#define CLK12_24_CTRL 0x1ac +#define MALI_CLK_CTRL 0x200 +#define MALI_STACK_CLK_CTRL 0x204 +#define DSPA_CLK_CTRL 0x220 +#define HEVCF_CLK_CTRL 0x240 +#define HCODEC_CLK_CTRL 0x244 +#define VPU_CLK_CTRL 0x260 +#define VAPB_CLK_CTRL 0x268 +#define VPU_CLKB_CTRL 0x280 +#define HDMI_CLK_CTRL 0x284 +#define HTX_CLK_CTRL 0x28c +#define HTX_CLK_CTRL1 0x290 +#define HRX_CLK_CTRL 0x294 +#define HRX_CLK_CTRL1 0x298 +#define HRX_CLK_CTRL2 0x29c +#define HRX_CLK_CTRL3 0x2a0 +#define VID_LOCK_CLK_CTRL 0x2a4 +#define VDIN_MEAS_CLK_CTRL 0x2a8 +#define VID_PLL_CLK_DIV 0x2b0 +#define VID_CLK_CTRL 0x2c0 +#define VID_CLK_CTRL2 0x2c4 +#define VID_CLK_DIV 0x2c8 +#define VIID_CLK_DIV 0x2cc +#define VIID_CLK_CTRL 0x2d0 +#define MIPI_CSI_PHY_CLK_CTRL 0x2e0 +#define DSI_MEAS_CLK_CTRL 0x2f4 + +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \ + MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0) + +#define A9_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define A9_COMP_GATE(_name, _reg, _bit, _iflags) \ + MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags)) + +static const struct clk_parent_data a9_sys_pclk_parents = { .fw_name = "sys" }; + +#define A9_SYS_PCLK(_name, _reg, _bit) \ + MESON_PCLK(a9_##_name, _reg, _bit, &a9_sys_pclk_parents, 0) + +static A9_SYS_PCLK(sys_am_axi, SYS_CLK_EN0_REG0, 0); +static A9_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1); +static A9_SYS_PCLK(sys_mipi_dsi0, SYS_CLK_EN0_REG0, 3); +static A9_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG0, 4); +static A9_SYS_PCLK(sys_amfc, SYS_CLK_EN0_REG0, 5); +static A9_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6); +static A9_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 7); +static A9_SYS_PCLK(sys_eth_axi, SYS_CLK_EN0_REG0, 8); +static A9_SYS_PCLK(sys_dp_apb, SYS_CLK_EN0_REG0, 9); +static A9_SYS_PCLK(sys_edptx_apb, SYS_CLK_EN0_REG0, 10); +static A9_SYS_PCLK(sys_u3hsg, SYS_CLK_EN0_REG0, 11); +static A9_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14); +static A9_SYS_PCLK(sys_glb, SYS_CLK_EN0_REG0, 15); +static A9_SYS_PCLK(sys_combo_dphy_apb, SYS_CLK_EN0_REG0, 17); +static A9_SYS_PCLK(sys_hdmirx_apb, SYS_CLK_EN0_REG0, 18); +static A9_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG0, 19); +static A9_SYS_PCLK(sys_mipi_dsi0_phy, SYS_CLK_EN0_REG0, 20); +static A9_SYS_PCLK(sys_can0, SYS_CLK_EN0_REG0, 21); +static A9_SYS_PCLK(sys_can1, SYS_CLK_EN0_REG0, 22); +static A9_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24); +static A9_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25); +static A9_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26); +static A9_SYS_PCLK(sys_sc, SYS_CLK_EN0_REG0, 27); +static A9_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28); +static A9_SYS_PCLK(sys_mipi_isp, SYS_CLK_EN0_REG0, 29); +static A9_SYS_PCLK(sys_msr, SYS_CLK_EN0_REG0, 30); +static A9_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0); +static A9_SYS_PCLK(sys_mipi_dsi1, SYS_CLK_EN0_REG1, 1); +static A9_SYS_PCLK(sys_mipi_dsi1_phy, SYS_CLK_EN0_REG1, 2); +static A9_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3); +static A9_SYS_PCLK(sys_eth_1g_mac, SYS_CLK_EN0_REG1, 4); +static A9_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5); +static A9_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10); +static A9_SYS_PCLK(sys_ts_a55, SYS_CLK_EN0_REG1, 11); +static A9_SYS_PCLK(sys_eth_1g_axi, SYS_CLK_EN0_REG1, 12); +static A9_SYS_PCLK(sys_ts_dos, SYS_CLK_EN0_REG1, 13); +static A9_SYS_PCLK(sys_u3drd_b, SYS_CLK_EN0_REG1, 14); +static A9_SYS_PCLK(sys_ts_core, SYS_CLK_EN0_REG1, 15); +static A9_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG1, 16); +static A9_SYS_PCLK(sys_csi_dig_clkin, SYS_CLK_EN0_REG1, 18); +static A9_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG1, 19); +static A9_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 20); +static A9_SYS_PCLK(sys_spisg, SYS_CLK_EN0_REG1, 21); +static A9_SYS_PCLK(sys_u2h, SYS_CLK_EN0_REG1, 23); +static A9_SYS_PCLK(sys_pcie_mac_a, SYS_CLK_EN0_REG1, 24); +static A9_SYS_PCLK(sys_u3drd_a, SYS_CLK_EN0_REG1, 25); +static A9_SYS_PCLK(sys_u2drd, SYS_CLK_EN0_REG1, 26); +static A9_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27); +static A9_SYS_PCLK(sys_pcie_mac_b, SYS_CLK_EN0_REG1, 28); +static A9_SYS_PCLK(sys_periph, SYS_CLK_EN0_REG1, 29); +static A9_SYS_PCLK(sys_pio, SYS_CLK_EN0_REG2, 0); +static A9_SYS_PCLK(sys_i3c, SYS_CLK_EN0_REG2, 1); +static A9_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2); +static A9_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3); +static A9_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4); +static A9_SYS_PCLK(sys_i2c_m_i, SYS_CLK_EN0_REG2, 5); +static A9_SYS_PCLK(sys_i2c_m_g, SYS_CLK_EN0_REG2, 6); +static A9_SYS_PCLK(sys_i2c_m_h, SYS_CLK_EN0_REG2, 7); +static A9_SYS_PCLK(sys_hdmi20_aes, SYS_CLK_EN0_REG2, 9); +static A9_SYS_PCLK(sys_csi2_host, SYS_CLK_EN0_REG2, 16); +static A9_SYS_PCLK(sys_csi2_adapt, SYS_CLK_EN0_REG2, 17); +static A9_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21); +static A9_SYS_PCLK(sys_pp_dma, SYS_CLK_EN0_REG2, 22); +static A9_SYS_PCLK(sys_pp_wrapper, SYS_CLK_EN0_REG2, 23); +static A9_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25); +static A9_SYS_PCLK(sys_csi2_phy, SYS_CLK_EN0_REG2, 27); +static A9_SYS_PCLK(sys_saradc, SYS_CLK_EN0_REG2, 28); +static A9_SYS_PCLK(sys_pwm_j, SYS_CLK_EN0_REG2, 30); +static A9_SYS_PCLK(sys_pwm_i, SYS_CLK_EN0_REG2, 31); +static A9_SYS_PCLK(sys_pwm_h, SYS_CLK_EN0_REG3, 0); +static A9_SYS_PCLK(sys_pwm_n, SYS_CLK_EN0_REG3, 8); +static A9_SYS_PCLK(sys_pwm_m, SYS_CLK_EN0_REG3, 9); +static A9_SYS_PCLK(sys_pwm_l, SYS_CLK_EN0_REG3, 10); +static A9_SYS_PCLK(sys_pwm_k, SYS_CLK_EN0_REG3, 11); + +/* Channel 5 is unconnected. */ +static u32 a9_sd_emmc_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 }; +static const struct clk_parent_data a9_sd_emmc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "hifi0", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "gp1", }, + { .fw_name = "gp0", } +}; + +static A9_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL0, 9, 0x7, a9_sd_emmc_parents, + a9_sd_emmc_parents_val_table); +static A9_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL0, 0, 7); +static A9_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL0, 8, 0); + +static A9_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL0, 25, 0x7, a9_sd_emmc_parents, + a9_sd_emmc_parents_val_table); +static A9_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL0, 16, 7); +static A9_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL0, 24, 0); + +static A9_COMP_SEL(sd_emmc_c, SD_EMMC_CLK_CTRL1, 9, 0x7, a9_sd_emmc_parents, + a9_sd_emmc_parents_val_table); +static A9_COMP_DIV(sd_emmc_c, SD_EMMC_CLK_CTRL1, 0, 7); +static A9_COMP_GATE(sd_emmc_c, SD_EMMC_CLK_CTRL1, 8, 0); + +static const struct clk_parent_data a9_pwm_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", } +}; + +static A9_COMP_SEL(pwm_h, PWM_CLK_H_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_h, PWM_CLK_H_CTRL, 0, 8); +static A9_COMP_GATE(pwm_h, PWM_CLK_H_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_i, PWM_CLK_I_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_i, PWM_CLK_I_CTRL, 0, 8); +static A9_COMP_GATE(pwm_i, PWM_CLK_I_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_j, PWM_CLK_J_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_j, PWM_CLK_J_CTRL, 0, 8); +static A9_COMP_GATE(pwm_j, PWM_CLK_J_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_k, PWM_CLK_K_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_k, PWM_CLK_K_CTRL, 0, 8); +static A9_COMP_GATE(pwm_k, PWM_CLK_K_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_l, PWM_CLK_L_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_l, PWM_CLK_L_CTRL, 0, 8); +static A9_COMP_GATE(pwm_l, PWM_CLK_L_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_m, PWM_CLK_M_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_m, PWM_CLK_M_CTRL, 0, 8); +static A9_COMP_GATE(pwm_m, PWM_CLK_M_CTRL, 8, 0); + +static A9_COMP_SEL(pwm_n, PWM_CLK_N_CTRL, 9, 0x7, a9_pwm_parents, NULL); +static A9_COMP_DIV(pwm_n, PWM_CLK_N_CTRL, 0, 8); +static A9_COMP_GATE(pwm_n, PWM_CLK_N_CTRL, 8, 0); + +static const struct clk_parent_data a9_spisg_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "gp0", } +}; + +static A9_COMP_SEL(spisg0, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL); +static A9_COMP_DIV(spisg0, SPISG_CLK_CTRL, 0, 6); +static A9_COMP_GATE(spisg0, SPISG_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(spisg1, SPISG_CLK_CTRL, 25, 0x7, a9_spisg_parents, NULL); +static A9_COMP_DIV(spisg1, SPISG_CLK_CTRL, 16, 6); +static A9_COMP_GATE(spisg1, SPISG_CLK_CTRL, 24, 0); + +static A9_COMP_SEL(spisg2, SPISG_CLK_CTRL1, 9, 0x7, a9_spisg_parents, NULL); +static A9_COMP_DIV(spisg2, SPISG_CLK_CTRL1, 0, 6); +static A9_COMP_GATE(spisg2, SPISG_CLK_CTRL1, 8, 0); + +static const struct clk_parent_data a9_saradc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", } +}; + +static A9_COMP_SEL(saradc, SAR_CLK_CTRL, 9, 0x7, a9_saradc_parents, NULL); +static A9_COMP_DIV(saradc, SAR_CLK_CTRL, 0, 8); +static A9_COMP_GATE(saradc, SAR_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_amfc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", } +}; + +static A9_COMP_SEL(amfc, AMFC_CLK_CTRL, 9, 0x7, a9_amfc_parents, NULL); +static A9_COMP_DIV(amfc, AMFC_CLK_CTRL, 0, 6); +static A9_COMP_GATE(amfc, AMFC_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_nna_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "gp2", }, + { .fw_name = "hifi0", } +}; + +static A9_COMP_SEL(nna, NNA_CLK_CTRL, 9, 0x7, a9_nna_parents, NULL); +static A9_COMP_DIV(nna, NNA_CLK_CTRL, 0, 7); +static A9_COMP_GATE(nna, NNA_CLK_CTRL, 8, 0); + +/* Channel 5 and 6 are unconnected. */ +static u32 a9_usb_250m_parents_val_table[] = { 0, 1, 2, 3, 4, 7 }; +static const struct clk_parent_data a9_usb_250m_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv7", }, + { .fw_name = "fdiv2p5", } +}; + +static A9_COMP_SEL(usb_250m, USB_CLK_CTRL, 9, 0x7, a9_usb_250m_parents, + a9_usb_250m_parents_val_table); +static A9_COMP_DIV(usb_250m, USB_CLK_CTRL, 0, 7); +static A9_COMP_GATE(usb_250m, USB_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_usb_48m_pre_parents[] = { + { .fw_name = "gp0", }, + { .fw_name = "gp1", }, + { .fw_name = "gp2", }, + { .fw_name = "fdiv2", } +}; + +static A9_COMP_SEL(usb_48m_pre, USB_CLK_CTRL, 25, 0x3, a9_usb_48m_pre_parents, NULL); +static A9_COMP_DIV(usb_48m_pre, USB_CLK_CTRL, 16, 7); +static A9_COMP_GATE(usb_48m_pre, USB_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_pcie_tl_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "gp0", }, + { .fw_name = "sys", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(pcie0_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents, NULL); +static A9_COMP_DIV(pcie0_tl, PCIE_TL_CLK_CTRL, 0, 7); +static A9_COMP_GATE(pcie0_tl, PCIE_TL_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(pcie1_tl, PCIE_TL_CLK_CTRL, 25, 0x7, a9_pcie_tl_parents, NULL); +static A9_COMP_DIV(pcie1_tl, PCIE_TL_CLK_CTRL, 16, 7); +static A9_COMP_GATE(pcie1_tl, PCIE_TL_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_cmpr_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "hifi0", }, + { .fw_name = "gp1", } +}; + +static A9_COMP_SEL(cmpr, CMPR_CLK_CTRL, 25, 0x7, a9_cmpr_parents, NULL); +static A9_COMP_DIV(cmpr, CMPR_CLK_CTRL, 16, 7); +static A9_COMP_GATE(cmpr, CMPR_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_dewarpa_parents[] = { + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "gp0", }, + { .fw_name = "hifi0", }, + { .fw_name = "gp1", } +}; + +static A9_COMP_SEL(dewarpa, DEWARP_CLK_CTRL, 9, 0x7, a9_dewarpa_parents, NULL); +static A9_COMP_DIV(dewarpa, DEWARP_CLK_CTRL, 0, 7); +static A9_COMP_GATE(dewarpa, DEWARP_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_sc_parents[] = { + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(sc_pre, SC_CLK_CTRL, 9, 0x7, a9_sc_parents, NULL); +static A9_COMP_DIV(sc_pre, SC_CLK_CTRL, 0, 8); +static A9_COMP_GATE(sc_pre, SC_CLK_CTRL, 8, 0); + +static struct clk_regmap a9_sc = { + .data = &(struct clk_regmap_div_data) { + .offset = SC_CLK_CTRL, + .shift = 16, + .width = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "sc", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_sc_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_dptx_apb2_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(dptx_apb2, DPTX_CLK_CTRL, 9, 0x7, a9_dptx_apb2_parents, NULL); +static A9_COMP_DIV(dptx_apb2, DPTX_CLK_CTRL, 0, 7); +static A9_COMP_GATE(dptx_apb2, DPTX_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_dptx_aud_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", } +}; + +static A9_COMP_SEL(dptx_aud, DPTX_CLK_CTRL, 25, 0x7, a9_dptx_aud_parents, NULL); +static A9_COMP_DIV(dptx_aud, DPTX_CLK_CTRL, 16, 7); +static A9_COMP_GATE(dptx_aud, DPTX_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_isp_parents[] = { + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "gp0", }, + { .fw_name = "hifi0", }, + { .fw_name = "fdiv2", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(isp, ISP_CLK_CTRL, 9, 0x7, a9_isp_parents, NULL); +static A9_COMP_DIV(isp, ISP_CLK_CTRL, 0, 7); +static A9_COMP_GATE(isp, ISP_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_cve_vge_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "hifi0", }, + { .fw_name = "fdiv5", }, + { .fw_name = "gp0", }, + { .fw_name = "rtc", } +}; + +static A9_COMP_SEL(cve, CVE_CLK_CTRL, 9, 0x7, a9_cve_vge_parents, NULL); +static A9_COMP_DIV(cve, CVE_CLK_CTRL, 0, 7); +static A9_COMP_GATE(cve, CVE_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(vge, CVE_CLK_CTRL, 25, 0x7, a9_cve_vge_parents, NULL); +static A9_COMP_DIV(vge, CVE_CLK_CTRL, 16, 7); +static A9_COMP_GATE(vge, CVE_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_pp_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "gp0", }, + { .fw_name = "sys", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(pp, PP_CLK_CTRL, 9, 0x7, a9_pp_parents, NULL); +static A9_COMP_DIV(pp, PP_CLK_CTRL, 0, 6); +static A9_COMP_GATE(pp, PP_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_dspa_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "gp2", }, + { .fw_name = "fdiv4", }, + { .fw_name = "hifi0", }, + { .fw_name = "rtc", } +}; + +static A9_COMP_SEL(dspa_0, DSPA_CLK_CTRL, 9, 0x7, a9_dspa_parents, NULL); +static A9_COMP_DIV(dspa_0, DSPA_CLK_CTRL, 0, 7); +static A9_COMP_GATE(dspa_0, DSPA_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(dspa_1, DSPA_CLK_CTRL, 25, 0x7, a9_dspa_parents, NULL); +static A9_COMP_DIV(dspa_1, DSPA_CLK_CTRL, 16, 7); +static A9_COMP_GATE(dspa_1, DSPA_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_dspa = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPA_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_dspa_0.hw, + &a9_dspa_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Channel 6 is unconnected. */ +static u32 a9_glb_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 7 }; +static const struct clk_parent_data a9_glb_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a9_dspa.hw }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .hw = &a9_isp.hw }, + { .fw_name = "rtc", } +}; + +static A9_COMP_SEL(glb, GLB_CLK_CTRL, 9, 0x7, a9_glb_parents, a9_glb_parents_val_table); +static A9_COMP_DIV(glb, GLB_CLK_CTRL, 0, 7); +static A9_COMP_GATE(glb, GLB_CLK_CTRL, 8, 0); + +static struct clk_regmap a9_usb_48m_dualdiv_in = { + .data = &(struct clk_regmap_gate_data) { + .offset = USB_CLK_CTRL, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_48m_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_usb_48m_pre.hw + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param a9_usb_48m_dualdiv_div_table[] = { + { 733, 732, 8, 11, 1 }, + { /* sentinel */ } +}; + +static struct clk_regmap a9_usb_48m_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data) { + .n1 = { + .reg_off = USB_CLK_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = USB_CLK_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = USB_CLK_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = USB_CLK_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = USB_CLK_CTRL0, + .shift = 28, + .width = 1, + }, + .table = a9_usb_48m_dualdiv_div_table, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_48m_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_usb_48m_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_usb_48m_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = USB_CLK_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_48m_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_usb_48m_dualdiv_in.hw, + &a9_usb_48m_dualdiv_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_usb_48m_dualdiv = { + .data = &(struct clk_regmap_gate_data) { + .offset = USB_CLK_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_48m_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_usb_48m_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_usb_48m = { + .data = &(struct clk_regmap_mux_data) { + .offset = USB_CLK_CTRL1, + .mask = 0x3, + .shift = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "usb_48m", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_usb_48m_pre.hw, + &a9_usb_48m_dualdiv.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Channel 2 is unconnected. */ +static u32 a9_can_pe_parents_val_table[] = { 0, 1, 3 }; +static const struct clk_parent_data a9_can_pe_parents[] = { + { .fw_name = "sys", }, + { .fw_name = "xtal", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(can0_pe, CAN_CLK_CTRL, 9, 0x7, a9_can_pe_parents, a9_can_pe_parents_val_table); +static A9_COMP_DIV(can0_pe, CAN_CLK_CTRL, 0, 7); +static A9_COMP_GATE(can0_pe, CAN_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(can1_pe, CAN_CLK_CTRL, 25, 0x7, a9_can_pe_parents, a9_can_pe_parents_val_table); +static A9_COMP_DIV(can1_pe, CAN_CLK_CTRL, 16, 7); +static A9_COMP_GATE(can1_pe, CAN_CLK_CTRL, 24, 0); + +static const struct clk_parent_data a9_can_filter_parents[] = { + { .fw_name = "sys", }, + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(can0_filter, CAN_CLK_CTRL1, 9, 0x7, a9_can_filter_parents, NULL); +static A9_COMP_DIV(can0_filter, CAN_CLK_CTRL1, 0, 7); +static A9_COMP_GATE(can0_filter, CAN_CLK_CTRL1, 8, 0); + +static A9_COMP_SEL(can1_filter, CAN_CLK_CTRL1, 25, 0x7, a9_can_filter_parents, NULL); +static A9_COMP_DIV(can1_filter, CAN_CLK_CTRL1, 16, 7); +static A9_COMP_GATE(can1_filter, CAN_CLK_CTRL1, 24, 0); + +static const struct clk_parent_data a9_i3c_parents[] = { + { .fw_name = "sys", }, + { .fw_name = "xtal", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(i3c, I3C_CLK_CTRL, 9, 0x7, a9_i3c_parents, NULL); +static A9_COMP_DIV(i3c, I3C_CLK_CTRL, 0, 8); +static A9_COMP_GATE(i3c, I3C_CLK_CTRL, 8, 0); + +static struct clk_regmap a9_ts_div = { + .data = &(struct clk_regmap_div_data) { + .offset = TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "ts_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_ts = { + .data = &(struct clk_regmap_gate_data) { + .offset = TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_ts_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor a9_eth_125m_div = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data) { + .name = "eth_125m_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fdiv2", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_eth_125m = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "eth_125m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_eth_125m_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Channel 1, 2, 3, 4, 5 and 6 are unconnected, + * Channel 7(ext_rmii) connects external PAD. Do not automatically reparent. + */ +static u32 a9_eth_rmii_parents_val_table[] = { 0, 7 }; +static const struct clk_parent_data a9_eth_rmii_parents[] = { + { .fw_name = "fdiv2", }, + { .fw_name = "ext_rmii", } +}; + +static struct clk_regmap a9_eth_rmii_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = ETH_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .table = a9_eth_rmii_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a9_eth_rmii_parents, + .num_parents = ARRAY_SIZE(a9_eth_rmii_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap a9_eth_rmii_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ETH_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_eth_rmii_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_eth_rmii = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_eth_rmii_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + .ops = &meson_vid_pll_div_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "hdmiout2", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a9_vid_pll_div.hw }, + { .fw_name = "hdmiout2", } + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Channel 12 (msr_clk) is managed by the clock measurement module and is not part of the clock + * tree. It depends on the measurement source selected through the measurement control registers. + * + * Channel 10, 11, 13, 14 and 16 are unconnected. + */ +static u32 a9_gen_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26}; +static const struct clk_parent_data a9_gen_parents[] = { + { .fw_name = "xtal" }, + { .fw_name = "rtc" }, + { .fw_name = "sysplldiv16" }, + { .fw_name = "ddr_test" }, + { .hw = &a9_vid_pll.hw }, + { .fw_name = "gp0" }, + { .fw_name = "hifi1" }, + { .fw_name = "hifi0" }, + { .fw_name = "gp1" }, + { .fw_name = "gp2" }, + { .fw_name = "dsudiv16" }, + { .fw_name = "cpudiv16" }, + { .fw_name = "a78div16" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" }, + { .fw_name = "mclk0" }, + { .fw_name = "mclk1" } +}; + +static A9_COMP_SEL(gen, GEN_CLK_CTRL, 12, 0x1f, a9_gen_parents, a9_gen_parents_val_table); +static A9_COMP_DIV(gen, GEN_CLK_CTRL, 0, 11); +static A9_COMP_GATE(gen, GEN_CLK_CTRL, 11, 0); + +static struct clk_regmap a9_24m_in = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "24m_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_12_24m = { + .data = &(struct clk_regmap_div_data) { + .offset = CLK12_24_CTRL, + .shift = 10, + .width = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "12_24m", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_24m_in.hw + }, + .num_parents = 1, + }, +}; + +static const struct clk_parent_data a9_mali_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp1", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", } +}; + +static A9_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, a9_mali_parents, NULL); +static A9_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7); +static A9_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, a9_mali_parents, NULL); +static A9_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7); +static A9_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = MALI_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_mali_0.hw, + &a9_mali_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static A9_COMP_SEL(mali_stack_0, MALI_STACK_CLK_CTRL, 9, 0x7, a9_mali_parents, NULL); +static A9_COMP_DIV(mali_stack_0, MALI_STACK_CLK_CTRL, 0, 7); +static A9_COMP_GATE(mali_stack_0, MALI_STACK_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(mali_stack_1, MALI_STACK_CLK_CTRL, 25, 0x7, a9_mali_parents, NULL); +static A9_COMP_DIV(mali_stack_1, MALI_STACK_CLK_CTRL, 16, 7); +static A9_COMP_GATE(mali_stack_1, MALI_STACK_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_mali_stack = { + .data = &(struct clk_regmap_mux_data){ + .offset = MALI_STACK_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_stack", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_mali_stack_0.hw, + &a9_mali_stack_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_hevcf_parents[] = { + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "hifi0", }, + { .fw_name = "gp1", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(hevcf_0, HEVCF_CLK_CTRL, 9, 0x7, a9_hevcf_parents, NULL); +static A9_COMP_DIV(hevcf_0, HEVCF_CLK_CTRL, 0, 7); +static A9_COMP_GATE(hevcf_0, HEVCF_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(hevcf_1, HEVCF_CLK_CTRL, 25, 0x7, a9_hevcf_parents, NULL); +static A9_COMP_DIV(hevcf_1, HEVCF_CLK_CTRL, 16, 7); +static A9_COMP_GATE(hevcf_1, HEVCF_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_hevcf = { + .data = &(struct clk_regmap_mux_data){ + .offset = HEVCF_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "hevcf", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hevcf_0.hw, + &a9_hevcf_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_hcodec_parents[] = { + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "hifi0", }, + { .fw_name = "gp0", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(hcodec_0, HCODEC_CLK_CTRL, 9, 0x7, a9_hcodec_parents, NULL); +static A9_COMP_DIV(hcodec_0, HCODEC_CLK_CTRL, 0, 7); +static A9_COMP_GATE(hcodec_0, HCODEC_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(hcodec_1, HCODEC_CLK_CTRL, 25, 0x7, a9_hcodec_parents, NULL); +static A9_COMP_DIV(hcodec_1, HCODEC_CLK_CTRL, 16, 7); +static A9_COMP_GATE(hcodec_1, HCODEC_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_hcodec = { + .data = &(struct clk_regmap_mux_data){ + .offset = HCODEC_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "hcodec", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hcodec_0.hw, + &a9_hcodec_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_vpu_parents[] = { + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "vid1", }, + { .fw_name = "fdiv2", }, + { .hw = &a9_vid_pll.hw }, + { .fw_name = "vid2", }, + { .fw_name = "gp1", } +}; + +static A9_COMP_SEL(vpu_0, VPU_CLK_CTRL, 9, 0x7, a9_vpu_parents, NULL); +static A9_COMP_DIV(vpu_0, VPU_CLK_CTRL, 0, 7); +static A9_COMP_GATE(vpu_0, VPU_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(vpu_1, VPU_CLK_CTRL, 25, 0x7, a9_vpu_parents, NULL); +static A9_COMP_DIV(vpu_1, VPU_CLK_CTRL, 16, 7); +static A9_COMP_GATE(vpu_1, VPU_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = VPU_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vpu_0.hw, + &a9_vpu_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_vapb_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "fdiv2", }, + { .hw = &a9_vid_pll.hw }, + { .fw_name = "hifi0", }, + { .fw_name = "fdiv2p5", } +}; + +static A9_COMP_SEL(vapb_0, VAPB_CLK_CTRL, 9, 0x7, a9_vapb_parents, NULL); +static A9_COMP_DIV(vapb_0, VAPB_CLK_CTRL, 0, 7); +static A9_COMP_GATE(vapb_0, VAPB_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static A9_COMP_SEL(vapb_1, VAPB_CLK_CTRL, 25, 0x7, a9_vapb_parents, NULL); +static A9_COMP_DIV(vapb_1, VAPB_CLK_CTRL, 16, 7); +static A9_COMP_GATE(vapb_1, VAPB_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap a9_vapb = { + .data = &(struct clk_regmap_mux_data){ + .offset = VAPB_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vapb_0.hw, + &a9_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_ge2d = { + .data = &(struct clk_regmap_gate_data) { + .offset = VAPB_CLK_CTRL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "ge2d", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vapb.hw, + }, + .num_parents = 1, + }, +}; + +static const struct clk_parent_data a9_vpu_clkb_tmp_parents[] = { + { .hw = &a9_vpu.hw }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", } +}; + +static A9_COMP_SEL(vpu_clkb_tmp, VPU_CLKB_CTRL, 25, 0x7, a9_vpu_clkb_tmp_parents, NULL); +static A9_COMP_DIV(vpu_clkb_tmp, VPU_CLKB_CTRL, 16, 4); +static A9_COMP_GATE(vpu_clkb_tmp, VPU_CLKB_CTRL, 24, 0); + +static struct clk_regmap a9_vpu_clkb_div = { + .data = &(struct clk_regmap_div_data) { + .offset = VPU_CLKB_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vpu_clkb_tmp.hw, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap a9_vpu_clkb = { + .data = &(struct clk_regmap_gate_data) { + .offset = VPU_CLKB_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vpu_clkb_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_hdmi_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(hdmitx_sys, HDMI_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmitx_sys, HDMI_CLK_CTRL, 0, 7); +static A9_COMP_GATE(hdmitx_sys, HDMI_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(hdmitx_prif, HTX_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmitx_prif, HTX_CLK_CTRL, 0, 7); +static A9_COMP_GATE(hdmitx_prif, HTX_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(hdmitx_200m, HTX_CLK_CTRL, 25, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmitx_200m, HTX_CLK_CTRL, 16, 7); +static A9_COMP_GATE(hdmitx_200m, HTX_CLK_CTRL, 24, 0); + +static A9_COMP_SEL(hdmitx_aud, HTX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmitx_aud, HTX_CLK_CTRL1, 0, 7); +static A9_COMP_GATE(hdmitx_aud, HTX_CLK_CTRL1, 8, 0); + +static A9_COMP_SEL(hdmirx_5m, HRX_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_5m, HRX_CLK_CTRL, 0, 7); +static A9_COMP_GATE(hdmirx_5m, HRX_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(hdmirx_2m, HRX_CLK_CTRL, 25, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_2m, HRX_CLK_CTRL, 16, 7); +static A9_COMP_GATE(hdmirx_2m, HRX_CLK_CTRL, 24, 0); + +static A9_COMP_SEL(hdmirx_cfg, HRX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_cfg, HRX_CLK_CTRL1, 0, 7); +static A9_COMP_GATE(hdmirx_cfg, HRX_CLK_CTRL1, 8, 0); + +static A9_COMP_SEL(hdmirx_hdcp2x, HRX_CLK_CTRL1, 25, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_hdcp2x, HRX_CLK_CTRL1, 16, 7); +static A9_COMP_GATE(hdmirx_hdcp2x, HRX_CLK_CTRL1, 24, 0); + +static A9_COMP_SEL(hdmirx_acr_ref, HRX_CLK_CTRL2, 25, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_acr_ref, HRX_CLK_CTRL2, 16, 7); +static A9_COMP_GATE(hdmirx_acr_ref, HRX_CLK_CTRL2, 24, 0); + +static A9_COMP_SEL(hdmirx_meter, HRX_CLK_CTRL3, 9, 0x7, a9_hdmi_parents, NULL); +static A9_COMP_DIV(hdmirx_meter, HRX_CLK_CTRL3, 0, 7); +static A9_COMP_GATE(hdmirx_meter, HRX_CLK_CTRL3, 8, 0); + +static struct clk_regmap a9_vid_pll_vclk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HDMI_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_vclk", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &a9_vid_pll.hw }, + { .fw_name = "hdmipix", } + }, + .num_parents = 2, + }, +}; + +static const struct clk_parent_data a9_vclk_parents[] = { + { .hw = &a9_vid_pll_vclk.hw }, + { .fw_name = "pix0", }, + { .fw_name = "vid1", }, + { .fw_name = "pix1", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "vid2", } +}; + +static struct clk_regmap a9_vclk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a9_vclk_parents, + .num_parents = ARRAY_SIZE(a9_vclk_parents), + }, +}; + +static struct clk_regmap a9_vclk0_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk0_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &a9_vclk0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vclk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vclk0_in.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vclk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &a9_vclk0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +#define A9_VCLK_GATE(_name, _reg, _bit, _parent) \ +struct clk_regmap a9_##_name##_en = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_en", \ + .ops = &clk_regmap_gate_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &(_parent).hw \ + }, \ + .num_parents = 1, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ +} + +#define A9_VCLK_DIV(_name, _div) \ +struct clk_fixed_factor a9_##_name = { \ + .mult = 1, \ + .div = (_div), \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_fixed_factor_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &a9_##_name##_en.hw \ + }, \ + .num_parents = 1, \ + .flags = CLK_SET_RATE_PARENT, \ + }, \ +} + +static A9_VCLK_GATE(vclk0_div1, VID_CLK_CTRL, 0, a9_vclk0); +static A9_VCLK_GATE(vclk0_div2, VID_CLK_CTRL, 1, a9_vclk0); +static A9_VCLK_DIV(vclk0_div2, 2); +static A9_VCLK_GATE(vclk0_div4, VID_CLK_CTRL, 2, a9_vclk0); +static A9_VCLK_DIV(vclk0_div4, 4); +static A9_VCLK_GATE(vclk0_div6, VID_CLK_CTRL, 3, a9_vclk0); +static A9_VCLK_DIV(vclk0_div6, 6); +static A9_VCLK_GATE(vclk0_div12, VID_CLK_CTRL, 4, a9_vclk0); +static A9_VCLK_DIV(vclk0_div12, 12); + +static struct clk_regmap a9_vclk1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VIID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = a9_vclk_parents, + .num_parents = ARRAY_SIZE(a9_vclk_parents), + }, +}; + +static struct clk_regmap a9_vclk1_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk1_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &a9_vclk1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vclk1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vclk1_in.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_vclk1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = VIID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &a9_vclk1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static A9_VCLK_GATE(vclk1_div1, VIID_CLK_CTRL, 0, a9_vclk1); +static A9_VCLK_GATE(vclk1_div2, VIID_CLK_CTRL, 1, a9_vclk1); +static A9_VCLK_DIV(vclk1_div2, 2); +static A9_VCLK_GATE(vclk1_div4, VIID_CLK_CTRL, 2, a9_vclk1); +static A9_VCLK_DIV(vclk1_div4, 4); +static A9_VCLK_GATE(vclk1_div6, VIID_CLK_CTRL, 3, a9_vclk1); +static A9_VCLK_DIV(vclk1_div6, 6); +static A9_VCLK_GATE(vclk1_div12, VIID_CLK_CTRL, 4, a9_vclk1); +static A9_VCLK_DIV(vclk1_div12, 12); + +/* Channel 5, 6 and 7 are unconnected */ +static u32 a9_vid_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *a9_vid_parents[] = { + &a9_vclk0_div1_en.hw, + &a9_vclk0_div2.hw, + &a9_vclk0_div4.hw, + &a9_vclk0_div6.hw, + &a9_vclk0_div12.hw, + &a9_vclk1_div1_en.hw, + &a9_vclk1_div2.hw, + &a9_vclk1_div4.hw, + &a9_vclk1_div6.hw, + &a9_vclk1_div12.hw +}; + +static struct clk_regmap a9_encoder0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "encoder0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_encoder0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "encoder0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_encoder0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_encoder1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VIID_CLK_DIV, + .mask = 0xf, + .shift = 8, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "encoder1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_encoder1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "encoder1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_encoder1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_vid_lock_parents[] = { + { .fw_name = "xtal", }, + { .hw = &a9_encoder0.hw }, + { .hw = &a9_encoder1.hw } +}; + +static A9_COMP_SEL(vid_lock, VID_LOCK_CLK_CTRL, 9, 0x7, a9_vid_lock_parents, NULL); +static A9_COMP_DIV(vid_lock, VID_LOCK_CLK_CTRL, 0, 7); +static A9_COMP_GATE(vid_lock, VID_LOCK_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_vdin_meas_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", } +}; + +static A9_COMP_SEL(vdin_meas, VDIN_MEAS_CLK_CTRL, 9, 0x7, a9_vdin_meas_parents, NULL); +static A9_COMP_DIV(vdin_meas, VDIN_MEAS_CLK_CTRL, 0, 7); +static A9_COMP_GATE(vdin_meas, VDIN_MEAS_CLK_CTRL, 8, 0); + +static struct clk_regmap a9_vdac_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_vdac = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_vdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_hdmitx0_pixel_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 16, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmitx0_pixel_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_hdmitx0_pixel = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmitx0_pixel", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hdmitx0_pixel_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_hdmitx0_fe_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 20, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmitx0_fe_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_hdmitx0_fe = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmitx0_fe", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hdmitx0_fe_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_hdmitx1_pixel_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 24, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmitx1_pixel_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_hdmitx1_pixel = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 12, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmitx1_pixel", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hdmitx1_pixel_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap a9_hdmitx1_fe_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 28, + .table = a9_vid_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmitx1_fe_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = a9_vid_parents, + .num_parents = ARRAY_SIZE(a9_vid_parents), + }, +}; + +static struct clk_regmap a9_hdmitx1_fe = { + .data = &(struct clk_regmap_gate_data){ + .offset = VID_CLK_CTRL2, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmitx1_fe", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &a9_hdmitx1_fe_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data a9_csi_phy_parents[] = { + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "gp0", }, + { .fw_name = "hifi0", }, + { .fw_name = "fdiv2", }, + { .fw_name = "xtal", } +}; + +static A9_COMP_SEL(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7, a9_csi_phy_parents, NULL); +static A9_COMP_DIV(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 0, 7); +static A9_COMP_GATE(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 8, 0); + +static const struct clk_parent_data a9_dsi_meas_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .hw = &a9_vid_pll.hw }, + { .fw_name = "gp0", }, + { .fw_name = "vid1", }, + { .fw_name = "vid2", } +}; + +static A9_COMP_SEL(dsi0_meas, DSI_MEAS_CLK_CTRL, 9, 0x7, a9_dsi_meas_parents, NULL); +static A9_COMP_DIV(dsi0_meas, DSI_MEAS_CLK_CTRL, 0, 7); +static A9_COMP_GATE(dsi0_meas, DSI_MEAS_CLK_CTRL, 8, 0); + +static A9_COMP_SEL(dsi1_meas, DSI_MEAS_CLK_CTRL, 25, 0x7, a9_dsi_meas_parents, NULL); +static A9_COMP_DIV(dsi1_meas, DSI_MEAS_CLK_CTRL, 16, 7); +static A9_COMP_GATE(dsi1_meas, DSI_MEAS_CLK_CTRL, 24, 0); + +static struct clk_hw *a9_peripherals_hw_clks[] = { + [CLKID_SYS_AM_AXI] = &a9_sys_am_axi.hw, + [CLKID_SYS_DOS] = &a9_sys_dos.hw, + [CLKID_SYS_MIPI_DSI0] = &a9_sys_mipi_dsi0.hw, + [CLKID_SYS_ETH_PHY] = &a9_sys_eth_phy.hw, + [CLKID_SYS_AMFC] = &a9_sys_amfc.hw, + [CLKID_SYS_MALI] = &a9_sys_mali.hw, + [CLKID_SYS_NNA] = &a9_sys_nna.hw, + [CLKID_SYS_ETH_AXI] = &a9_sys_eth_axi.hw, + [CLKID_SYS_DP_APB] = &a9_sys_dp_apb.hw, + [CLKID_SYS_EDPTX_APB] = &a9_sys_edptx_apb.hw, + [CLKID_SYS_U3HSG] = &a9_sys_u3hsg.hw, + [CLKID_SYS_AUCPU] = &a9_sys_aucpu.hw, + [CLKID_SYS_GLB] = &a9_sys_glb.hw, + [CLKID_SYS_COMBO_DPHY_APB] = &a9_sys_combo_dphy_apb.hw, + [CLKID_SYS_HDMIRX_APB] = &a9_sys_hdmirx_apb.hw, + [CLKID_SYS_HDMIRX_PCLK] = &a9_sys_hdmirx_pclk.hw, + [CLKID_SYS_MIPI_DSI0_PHY] = &a9_sys_mipi_dsi0_phy.hw, + [CLKID_SYS_CAN0] = &a9_sys_can0.hw, + [CLKID_SYS_CAN1] = &a9_sys_can1.hw, + [CLKID_SYS_SD_EMMC_A] = &a9_sys_sd_emmc_a.hw, + [CLKID_SYS_SD_EMMC_B] = &a9_sys_sd_emmc_b.hw, + [CLKID_SYS_SD_EMMC_C] = &a9_sys_sd_emmc_c.hw, + [CLKID_SYS_SC] = &a9_sys_sc.hw, + [CLKID_SYS_ACODEC] = &a9_sys_acodec.hw, + [CLKID_SYS_MIPI_ISP] = &a9_sys_mipi_isp.hw, + [CLKID_SYS_MSR] = &a9_sys_msr.hw, + [CLKID_SYS_AUDIO] = &a9_sys_audio.hw, + [CLKID_SYS_MIPI_DSI1] = &a9_sys_mipi_dsi1.hw, + [CLKID_SYS_MIPI_DSI1_PHY] = &a9_sys_mipi_dsi1_phy.hw, + [CLKID_SYS_ETH] = &a9_sys_eth.hw, + [CLKID_SYS_ETH_1G_MAC] = &a9_sys_eth_1g_mac.hw, + [CLKID_SYS_UART_A] = &a9_sys_uart_a.hw, + [CLKID_SYS_UART_F] = &a9_sys_uart_f.hw, + [CLKID_SYS_TS_A55] = &a9_sys_ts_a55.hw, + [CLKID_SYS_ETH_1G_AXI] = &a9_sys_eth_1g_axi.hw, + [CLKID_SYS_TS_DOS] = &a9_sys_ts_dos.hw, + [CLKID_SYS_U3DRD_B] = &a9_sys_u3drd_b.hw, + [CLKID_SYS_TS_CORE] = &a9_sys_ts_core.hw, + [CLKID_SYS_TS_PLL] = &a9_sys_ts_pll.hw, + [CLKID_SYS_CSI_DIG_CLKIN] = &a9_sys_csi_dig_clkin.hw, + [CLKID_SYS_CVE] = &a9_sys_cve.hw, + [CLKID_SYS_GE2D] = &a9_sys_ge2d.hw, + [CLKID_SYS_SPISG] = &a9_sys_spisg.hw, + [CLKID_SYS_U2H] = &a9_sys_u2h.hw, + [CLKID_SYS_PCIE_MAC_A] = &a9_sys_pcie_mac_a.hw, + [CLKID_SYS_U3DRD_A] = &a9_sys_u3drd_a.hw, + [CLKID_SYS_U2DRD] = &a9_sys_u2drd.hw, + [CLKID_SYS_PCIE_PHY] = &a9_sys_pcie_phy.hw, + [CLKID_SYS_PCIE_MAC_B] = &a9_sys_pcie_mac_b.hw, + [CLKID_SYS_PERIPH] = &a9_sys_periph.hw, + [CLKID_SYS_PIO] = &a9_sys_pio.hw, + [CLKID_SYS_I3C] = &a9_sys_i3c.hw, + [CLKID_SYS_I2C_M_E] = &a9_sys_i2c_m_e.hw, + [CLKID_SYS_I2C_M_F] = &a9_sys_i2c_m_f.hw, + [CLKID_SYS_HDMITX_APB] = &a9_sys_hdmitx_apb.hw, + [CLKID_SYS_I2C_M_I] = &a9_sys_i2c_m_i.hw, + [CLKID_SYS_I2C_M_G] = &a9_sys_i2c_m_g.hw, + [CLKID_SYS_I2C_M_H] = &a9_sys_i2c_m_h.hw, + [CLKID_SYS_HDMI20_AES] = &a9_sys_hdmi20_aes.hw, + [CLKID_SYS_CSI2_HOST] = &a9_sys_csi2_host.hw, + [CLKID_SYS_CSI2_ADAPT] = &a9_sys_csi2_adapt.hw, + [CLKID_SYS_DSPA] = &a9_sys_dspa.hw, + [CLKID_SYS_PP_DMA] = &a9_sys_pp_dma.hw, + [CLKID_SYS_PP_WRAPPER] = &a9_sys_pp_wrapper.hw, + [CLKID_SYS_VPU_INTR] = &a9_sys_vpu_intr.hw, + [CLKID_SYS_CSI2_PHY] = &a9_sys_csi2_phy.hw, + [CLKID_SYS_SARADC] = &a9_sys_saradc.hw, + [CLKID_SYS_PWM_J] = &a9_sys_pwm_j.hw, + [CLKID_SYS_PWM_I] = &a9_sys_pwm_i.hw, + [CLKID_SYS_PWM_H] = &a9_sys_pwm_h.hw, + [CLKID_SYS_PWM_N] = &a9_sys_pwm_n.hw, + [CLKID_SYS_PWM_M] = &a9_sys_pwm_m.hw, + [CLKID_SYS_PWM_L] = &a9_sys_pwm_l.hw, + [CLKID_SYS_PWM_K] = &a9_sys_pwm_k.hw, + [CLKID_SD_EMMC_A_SEL] = &a9_sd_emmc_a_sel.hw, + [CLKID_SD_EMMC_A_DIV] = &a9_sd_emmc_a_div.hw, + [CLKID_SD_EMMC_A] = &a9_sd_emmc_a.hw, + [CLKID_SD_EMMC_B_SEL] = &a9_sd_emmc_b_sel.hw, + [CLKID_SD_EMMC_B_DIV] = &a9_sd_emmc_b_div.hw, + [CLKID_SD_EMMC_B] = &a9_sd_emmc_b.hw, + [CLKID_SD_EMMC_C_SEL] = &a9_sd_emmc_c_sel.hw, + [CLKID_SD_EMMC_C_DIV] = &a9_sd_emmc_c_div.hw, + [CLKID_SD_EMMC_C] = &a9_sd_emmc_c.hw, + [CLKID_PWM_H_SEL] = &a9_pwm_h_sel.hw, + [CLKID_PWM_H_DIV] = &a9_pwm_h_div.hw, + [CLKID_PWM_H] = &a9_pwm_h.hw, + [CLKID_PWM_I_SEL] = &a9_pwm_i_sel.hw, + [CLKID_PWM_I_DIV] = &a9_pwm_i_div.hw, + [CLKID_PWM_I] = &a9_pwm_i.hw, + [CLKID_PWM_J_SEL] = &a9_pwm_j_sel.hw, + [CLKID_PWM_J_DIV] = &a9_pwm_j_div.hw, + [CLKID_PWM_J] = &a9_pwm_j.hw, + [CLKID_PWM_K_SEL] = &a9_pwm_k_sel.hw, + [CLKID_PWM_K_DIV] = &a9_pwm_k_div.hw, + [CLKID_PWM_K] = &a9_pwm_k.hw, + [CLKID_PWM_L_SEL] = &a9_pwm_l_sel.hw, + [CLKID_PWM_L_DIV] = &a9_pwm_l_div.hw, + [CLKID_PWM_L] = &a9_pwm_l.hw, + [CLKID_PWM_M_SEL] = &a9_pwm_m_sel.hw, + [CLKID_PWM_M_DIV] = &a9_pwm_m_div.hw, + [CLKID_PWM_M] = &a9_pwm_m.hw, + [CLKID_PWM_N_SEL] = &a9_pwm_n_sel.hw, + [CLKID_PWM_N_DIV] = &a9_pwm_n_div.hw, + [CLKID_PWM_N] = &a9_pwm_n.hw, + [CLKID_SPISG0_SEL] = &a9_spisg0_sel.hw, + [CLKID_SPISG0_DIV] = &a9_spisg0_div.hw, + [CLKID_SPISG0] = &a9_spisg0.hw, + [CLKID_SPISG1_SEL] = &a9_spisg1_sel.hw, + [CLKID_SPISG1_DIV] = &a9_spisg1_div.hw, + [CLKID_SPISG1] = &a9_spisg1.hw, + [CLKID_SPISG2_SEL] = &a9_spisg2_sel.hw, + [CLKID_SPISG2_DIV] = &a9_spisg2_div.hw, + [CLKID_SPISG2] = &a9_spisg2.hw, + [CLKID_SARADC_SEL] = &a9_saradc_sel.hw, + [CLKID_SARADC_DIV] = &a9_saradc_div.hw, + [CLKID_SARADC] = &a9_saradc.hw, + [CLKID_AMFC_SEL] = &a9_amfc_sel.hw, + [CLKID_AMFC_DIV] = &a9_amfc_div.hw, + [CLKID_AMFC] = &a9_amfc.hw, + [CLKID_NNA_SEL] = &a9_nna_sel.hw, + [CLKID_NNA_DIV] = &a9_nna_div.hw, + [CLKID_NNA] = &a9_nna.hw, + [CLKID_USB_250M_SEL] = &a9_usb_250m_sel.hw, + [CLKID_USB_250M_DIV] = &a9_usb_250m_div.hw, + [CLKID_USB_250M] = &a9_usb_250m.hw, + [CLKID_USB_48M_PRE_SEL] = &a9_usb_48m_pre_sel.hw, + [CLKID_USB_48M_PRE_DIV] = &a9_usb_48m_pre_div.hw, + [CLKID_USB_48M_PRE] = &a9_usb_48m_pre.hw, + [CLKID_PCIE0_TL_SEL] = &a9_pcie0_tl_sel.hw, + [CLKID_PCIE0_TL_DIV] = &a9_pcie0_tl_div.hw, + [CLKID_PCIE0_TL] = &a9_pcie0_tl.hw, + [CLKID_PCIE1_TL_SEL] = &a9_pcie1_tl_sel.hw, + [CLKID_PCIE1_TL_DIV] = &a9_pcie1_tl_div.hw, + [CLKID_PCIE1_TL] = &a9_pcie1_tl.hw, + [CLKID_CMPR_SEL] = &a9_cmpr_sel.hw, + [CLKID_CMPR_DIV] = &a9_cmpr_div.hw, + [CLKID_CMPR] = &a9_cmpr.hw, + [CLKID_DEWARPA_SEL] = &a9_dewarpa_sel.hw, + [CLKID_DEWARPA_DIV] = &a9_dewarpa_div.hw, + [CLKID_DEWARPA] = &a9_dewarpa.hw, + [CLKID_SC_PRE_SEL] = &a9_sc_pre_sel.hw, + [CLKID_SC_PRE_DIV] = &a9_sc_pre_div.hw, + [CLKID_SC_PRE] = &a9_sc_pre.hw, + [CLKID_SC] = &a9_sc.hw, + [CLKID_DPTX_APB2_SEL] = &a9_dptx_apb2_sel.hw, + [CLKID_DPTX_APB2_DIV] = &a9_dptx_apb2_div.hw, + [CLKID_DPTX_APB2] = &a9_dptx_apb2.hw, + [CLKID_DPTX_AUD_SEL] = &a9_dptx_aud_sel.hw, + [CLKID_DPTX_AUD_DIV] = &a9_dptx_aud_div.hw, + [CLKID_DPTX_AUD] = &a9_dptx_aud.hw, + [CLKID_ISP_SEL] = &a9_isp_sel.hw, + [CLKID_ISP_DIV] = &a9_isp_div.hw, + [CLKID_ISP] = &a9_isp.hw, + [CLKID_CVE_SEL] = &a9_cve_sel.hw, + [CLKID_CVE_DIV] = &a9_cve_div.hw, + [CLKID_CVE] = &a9_cve.hw, + [CLKID_VGE_SEL] = &a9_vge_sel.hw, + [CLKID_VGE_DIV] = &a9_vge_div.hw, + [CLKID_VGE] = &a9_vge.hw, + [CLKID_PP_SEL] = &a9_pp_sel.hw, + [CLKID_PP_DIV] = &a9_pp_div.hw, + [CLKID_PP] = &a9_pp.hw, + [CLKID_GLB_SEL] = &a9_glb_sel.hw, + [CLKID_GLB_DIV] = &a9_glb_div.hw, + [CLKID_GLB] = &a9_glb.hw, + [CLKID_USB_48M_DUALDIV_IN] = &a9_usb_48m_dualdiv_in.hw, + [CLKID_USB_48M_DUALDIV_DIV] = &a9_usb_48m_dualdiv_div.hw, + [CLKID_USB_48M_DUALDIV_SEL] = &a9_usb_48m_dualdiv_sel.hw, + [CLKID_USB_48M_DUALDIV] = &a9_usb_48m_dualdiv.hw, + [CLKID_USB_48M] = &a9_usb_48m.hw, + [CLKID_CAN0_PE_SEL] = &a9_can0_pe_sel.hw, + [CLKID_CAN0_PE_DIV] = &a9_can0_pe_div.hw, + [CLKID_CAN0_PE] = &a9_can0_pe.hw, + [CLKID_CAN1_PE_SEL] = &a9_can1_pe_sel.hw, + [CLKID_CAN1_PE_DIV] = &a9_can1_pe_div.hw, + [CLKID_CAN1_PE] = &a9_can1_pe.hw, + [CLKID_CAN0_FILTER_SEL] = &a9_can0_filter_sel.hw, + [CLKID_CAN0_FILTER_DIV] = &a9_can0_filter_div.hw, + [CLKID_CAN0_FILTER] = &a9_can0_filter.hw, + [CLKID_CAN1_FILTER_SEL] = &a9_can1_filter_sel.hw, + [CLKID_CAN1_FILTER_DIV] = &a9_can1_filter_div.hw, + [CLKID_CAN1_FILTER] = &a9_can1_filter.hw, + [CLKID_I3C_SEL] = &a9_i3c_sel.hw, + [CLKID_I3C_DIV] = &a9_i3c_div.hw, + [CLKID_I3C] = &a9_i3c.hw, + [CLKID_TS_DIV] = &a9_ts_div.hw, + [CLKID_TS] = &a9_ts.hw, + [CLKID_ETH_125M_DIV] = &a9_eth_125m_div.hw, + [CLKID_ETH_125M] = &a9_eth_125m.hw, + [CLKID_ETH_RMII_SEL] = &a9_eth_rmii_sel.hw, + [CLKID_ETH_RMII_DIV] = &a9_eth_rmii_div.hw, + [CLKID_ETH_RMII] = &a9_eth_rmii.hw, + [CLKID_GEN_SEL] = &a9_gen_sel.hw, + [CLKID_GEN_DIV] = &a9_gen_div.hw, + [CLKID_GEN] = &a9_gen.hw, + [CLKID_CLK24M_IN] = &a9_24m_in.hw, + [CLKID_CLK12_24M] = &a9_12_24m.hw, + [CLKID_MALI_0_SEL] = &a9_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &a9_mali_0_div.hw, + [CLKID_MALI_0] = &a9_mali_0.hw, + [CLKID_MALI_1_SEL] = &a9_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &a9_mali_1_div.hw, + [CLKID_MALI_1] = &a9_mali_1.hw, + [CLKID_MALI] = &a9_mali.hw, + [CLKID_MALI_STACK_0_SEL] = &a9_mali_stack_0_sel.hw, + [CLKID_MALI_STACK_0_DIV] = &a9_mali_stack_0_div.hw, + [CLKID_MALI_STACK_0] = &a9_mali_stack_0.hw, + [CLKID_MALI_STACK_1_SEL] = &a9_mali_stack_1_sel.hw, + [CLKID_MALI_STACK_1_DIV] = &a9_mali_stack_1_div.hw, + [CLKID_MALI_STACK_1] = &a9_mali_stack_1.hw, + [CLKID_MALI_STACK] = &a9_mali_stack.hw, + [CLKID_DSPA_0_SEL] = &a9_dspa_0_sel.hw, + [CLKID_DSPA_0_DIV] = &a9_dspa_0_div.hw, + [CLKID_DSPA_0] = &a9_dspa_0.hw, + [CLKID_DSPA_1_SEL] = &a9_dspa_1_sel.hw, + [CLKID_DSPA_1_DIV] = &a9_dspa_1_div.hw, + [CLKID_DSPA_1] = &a9_dspa_1.hw, + [CLKID_DSPA] = &a9_dspa.hw, + [CLKID_HEVCF_0_SEL] = &a9_hevcf_0_sel.hw, + [CLKID_HEVCF_0_DIV] = &a9_hevcf_0_div.hw, + [CLKID_HEVCF_0] = &a9_hevcf_0.hw, + [CLKID_HEVCF_1_SEL] = &a9_hevcf_1_sel.hw, + [CLKID_HEVCF_1_DIV] = &a9_hevcf_1_div.hw, + [CLKID_HEVCF_1] = &a9_hevcf_1.hw, + [CLKID_HEVCF] = &a9_hevcf.hw, + [CLKID_HCODEC_0_SEL] = &a9_hcodec_0_sel.hw, + [CLKID_HCODEC_0_DIV] = &a9_hcodec_0_div.hw, + [CLKID_HCODEC_0] = &a9_hcodec_0.hw, + [CLKID_HCODEC_1_SEL] = &a9_hcodec_1_sel.hw, + [CLKID_HCODEC_1_DIV] = &a9_hcodec_1_div.hw, + [CLKID_HCODEC_1] = &a9_hcodec_1.hw, + [CLKID_HCODEC] = &a9_hcodec.hw, + [CLKID_VPU_0_SEL] = &a9_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &a9_vpu_0_div.hw, + [CLKID_VPU_0] = &a9_vpu_0.hw, + [CLKID_VPU_1_SEL] = &a9_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &a9_vpu_1_div.hw, + [CLKID_VPU_1] = &a9_vpu_1.hw, + [CLKID_VPU] = &a9_vpu.hw, + [CLKID_VAPB_0_SEL] = &a9_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &a9_vapb_0_div.hw, + [CLKID_VAPB_0] = &a9_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &a9_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &a9_vapb_1_div.hw, + [CLKID_VAPB_1] = &a9_vapb_1.hw, + [CLKID_VAPB] = &a9_vapb.hw, + [CLKID_GE2D] = &a9_ge2d.hw, + [CLKID_VPU_CLKB_TMP_SEL] = &a9_vpu_clkb_tmp_sel.hw, + [CLKID_VPU_CLKB_TMP_DIV] = &a9_vpu_clkb_tmp_div.hw, + [CLKID_VPU_CLKB_TMP] = &a9_vpu_clkb_tmp.hw, + [CLKID_VPU_CLKB_DIV] = &a9_vpu_clkb_div.hw, + [CLKID_VPU_CLKB] = &a9_vpu_clkb.hw, + [CLKID_HDMITX_SYS_SEL] = &a9_hdmitx_sys_sel.hw, + [CLKID_HDMITX_SYS_DIV] = &a9_hdmitx_sys_div.hw, + [CLKID_HDMITX_SYS] = &a9_hdmitx_sys.hw, + [CLKID_HDMITX_PRIF_SEL] = &a9_hdmitx_prif_sel.hw, + [CLKID_HDMITX_PRIF_DIV] = &a9_hdmitx_prif_div.hw, + [CLKID_HDMITX_PRIF] = &a9_hdmitx_prif.hw, + [CLKID_HDMITX_200M_SEL] = &a9_hdmitx_200m_sel.hw, + [CLKID_HDMITX_200M_DIV] = &a9_hdmitx_200m_div.hw, + [CLKID_HDMITX_200M] = &a9_hdmitx_200m.hw, + [CLKID_HDMITX_AUD_SEL] = &a9_hdmitx_aud_sel.hw, + [CLKID_HDMITX_AUD_DIV] = &a9_hdmitx_aud_div.hw, + [CLKID_HDMITX_AUD] = &a9_hdmitx_aud.hw, + [CLKID_HDMIRX_5M_SEL] = &a9_hdmirx_5m_sel.hw, + [CLKID_HDMIRX_5M_DIV] = &a9_hdmirx_5m_div.hw, + [CLKID_HDMIRX_5M] = &a9_hdmirx_5m.hw, + [CLKID_HDMIRX_2M_SEL] = &a9_hdmirx_2m_sel.hw, + [CLKID_HDMIRX_2M_DIV] = &a9_hdmirx_2m_div.hw, + [CLKID_HDMIRX_2M] = &a9_hdmirx_2m.hw, + [CLKID_HDMIRX_CFG_SEL] = &a9_hdmirx_cfg_sel.hw, + [CLKID_HDMIRX_CFG_DIV] = &a9_hdmirx_cfg_div.hw, + [CLKID_HDMIRX_CFG] = &a9_hdmirx_cfg.hw, + [CLKID_HDMIRX_HDCP2X_SEL] = &a9_hdmirx_hdcp2x_sel.hw, + [CLKID_HDMIRX_HDCP2X_DIV] = &a9_hdmirx_hdcp2x_div.hw, + [CLKID_HDMIRX_HDCP2X] = &a9_hdmirx_hdcp2x.hw, + [CLKID_HDMIRX_ACR_REF_SEL] = &a9_hdmirx_acr_ref_sel.hw, + [CLKID_HDMIRX_ACR_REF_DIV] = &a9_hdmirx_acr_ref_div.hw, + [CLKID_HDMIRX_ACR_REF] = &a9_hdmirx_acr_ref.hw, + [CLKID_HDMIRX_METER_SEL] = &a9_hdmirx_meter_sel.hw, + [CLKID_HDMIRX_METER_DIV] = &a9_hdmirx_meter_div.hw, + [CLKID_HDMIRX_METER] = &a9_hdmirx_meter.hw, + [CLKID_VID_LOCK_SEL] = &a9_vid_lock_sel.hw, + [CLKID_VID_LOCK_DIV] = &a9_vid_lock_div.hw, + [CLKID_VID_LOCK] = &a9_vid_lock.hw, + [CLKID_VDIN_MEAS_SEL] = &a9_vdin_meas_sel.hw, + [CLKID_VDIN_MEAS_DIV] = &a9_vdin_meas_div.hw, + [CLKID_VDIN_MEAS] = &a9_vdin_meas.hw, + [CLKID_VID_PLL_DIV] = &a9_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &a9_vid_pll_sel.hw, + [CLKID_VID_PLL] = &a9_vid_pll.hw, + [CLKID_VID_PLL_VCLK] = &a9_vid_pll_vclk.hw, + [CLKID_VCLK0_SEL] = &a9_vclk0_sel.hw, + [CLKID_VCLK0_IN] = &a9_vclk0_in.hw, + [CLKID_VCLK0_DIV] = &a9_vclk0_div.hw, + [CLKID_VCLK0] = &a9_vclk0.hw, + [CLKID_VCLK0_DIV1_EN] = &a9_vclk0_div1_en.hw, + [CLKID_VCLK0_DIV2_EN] = &a9_vclk0_div2_en.hw, + [CLKID_VCLK0_DIV2] = &a9_vclk0_div2.hw, + [CLKID_VCLK0_DIV4_EN] = &a9_vclk0_div4_en.hw, + [CLKID_VCLK0_DIV4] = &a9_vclk0_div4.hw, + [CLKID_VCLK0_DIV6_EN] = &a9_vclk0_div6_en.hw, + [CLKID_VCLK0_DIV6] = &a9_vclk0_div6.hw, + [CLKID_VCLK0_DIV12_EN] = &a9_vclk0_div12_en.hw, + [CLKID_VCLK0_DIV12] = &a9_vclk0_div12.hw, + [CLKID_VCLK1_SEL] = &a9_vclk1_sel.hw, + [CLKID_VCLK1_IN] = &a9_vclk1_in.hw, + [CLKID_VCLK1_DIV] = &a9_vclk1_div.hw, + [CLKID_VCLK1] = &a9_vclk1.hw, + [CLKID_VCLK1_DIV1_EN] = &a9_vclk1_div1_en.hw, + [CLKID_VCLK1_DIV2_EN] = &a9_vclk1_div2_en.hw, + [CLKID_VCLK1_DIV2] = &a9_vclk1_div2.hw, + [CLKID_VCLK1_DIV4_EN] = &a9_vclk1_div4_en.hw, + [CLKID_VCLK1_DIV4] = &a9_vclk1_div4.hw, + [CLKID_VCLK1_DIV6_EN] = &a9_vclk1_div6_en.hw, + [CLKID_VCLK1_DIV6] = &a9_vclk1_div6.hw, + [CLKID_VCLK1_DIV12_EN] = &a9_vclk1_div12_en.hw, + [CLKID_VCLK1_DIV12] = &a9_vclk1_div12.hw, + [CLKID_VDAC_SEL] = &a9_vdac_sel.hw, + [CLKID_VDAC] = &a9_vdac.hw, + [CLKID_ENCODER0_SEL] = &a9_encoder0_sel.hw, + [CLKID_ENCODER0] = &a9_encoder0.hw, + [CLKID_ENCODER1_SEL] = &a9_encoder1_sel.hw, + [CLKID_ENCODER1] = &a9_encoder1.hw, + [CLKID_HDMITX0_PIXEL_SEL] = &a9_hdmitx0_pixel_sel.hw, + [CLKID_HDMITX0_PIXEL] = &a9_hdmitx0_pixel.hw, + [CLKID_HDMITX0_FE_SEL] = &a9_hdmitx0_fe_sel.hw, + [CLKID_HDMITX0_FE] = &a9_hdmitx0_fe.hw, + [CLKID_HDMITX1_PIXEL_SEL] = &a9_hdmitx1_pixel_sel.hw, + [CLKID_HDMITX1_PIXEL] = &a9_hdmitx1_pixel.hw, + [CLKID_HDMITX1_FE_SEL] = &a9_hdmitx1_fe_sel.hw, + [CLKID_HDMITX1_FE] = &a9_hdmitx1_fe.hw, + [CLKID_CSI_PHY_SEL] = &a9_csi_phy_sel.hw, + [CLKID_CSI_PHY_DIV] = &a9_csi_phy_div.hw, + [CLKID_CSI_PHY] = &a9_csi_phy.hw, + [CLKID_DSI0_MEAS_SEL] = &a9_dsi0_meas_sel.hw, + [CLKID_DSI0_MEAS_DIV] = &a9_dsi0_meas_div.hw, + [CLKID_DSI0_MEAS] = &a9_dsi0_meas.hw, + [CLKID_DSI1_MEAS_SEL] = &a9_dsi1_meas_sel.hw, + [CLKID_DSI1_MEAS_DIV] = &a9_dsi1_meas_div.hw, + [CLKID_DSI1_MEAS] = &a9_dsi1_meas.hw, +}; + +static const struct meson_clkc_data a9_peripherals_clkc_data = { + .hw_clks = { + .hws = a9_peripherals_hw_clks, + .num = ARRAY_SIZE(a9_peripherals_hw_clks), + }, +}; + +static const struct of_device_id a9_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,a9-peripherals-clkc", + .data = &a9_peripherals_clkc_data, + }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, a9_peripherals_clkc_match_table); + +static struct platform_driver a9_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "a9-peripherals-clkc", + .of_match_table = a9_peripherals_clkc_match_table, + }, +}; +module_platform_driver(a9_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic A9 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c new file mode 100644 index 000000000..902fbd340 --- /dev/null +++ b/drivers/clk/meson/axg-aoclk.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + */ +#include +#include +#include +#include +#include +#include "meson-aoclk.h" + +#include "clk-regmap.h" +#include "clk-dualdiv.h" + +#include +#include + +/* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. + */ +#define AO_RTI_PWR_CNTL_REG1 0x0C +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_SAR_CLK 0x90 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + +static const struct clk_parent_data axg_ao_pclk_parents = { .fw_name = "mpeg-clk" }; + +#define AXG_AO_GATE(_name, _bit, _flags) \ + MESON_PCLK(axg_ao_##_name, AO_RTI_GEN_CNTL_REG0, _bit, \ + &axg_ao_pclk_parents, _flags) + +static AXG_AO_GATE(remote, 0, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(i2c_master, 1, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(i2c_slave, 2, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(uart1, 3, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(uart2, 5, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(ir_blaster, 6, CLK_IGNORE_UNUSED); +static AXG_AO_GATE(saradc, 7, CLK_IGNORE_UNUSED); + +static struct clk_regmap axg_ao_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_ao_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_cts_oscin.hw + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param axg_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap axg_ao_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = axg_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_32k_pre.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_ao_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_32k_div.hw, + &axg_ao_32k_pre.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_ao_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_ao_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &axg_ao_32k.hw }, + { .fw_name = "ext_32k-0", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_ao_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 8, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + /* + * NOTE: this is one of the infamous clock the pwm driver + * can request directly by its global name. It's wrong but + * there is not much we can do about it until the support + * for the old pwm bindings is dropped + */ + .name = "axg_ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &axg_ao_cts_rtc_oscin.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_ao_saradc_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_SAR_CLK, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &axg_ao_clk81.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap axg_ao_saradc_div = { + .data = &(struct clk_regmap_div_data) { + .offset = AO_SAR_CLK, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_saradc_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_ao_saradc_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = AO_SAR_CLK, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_ao_saradc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const unsigned int axg_ao_reset[] = { + [RESET_AO_REMOTE] = 16, + [RESET_AO_I2C_MASTER] = 18, + [RESET_AO_I2C_SLAVE] = 19, + [RESET_AO_UART1] = 17, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_BLASTER] = 23, +}; + +static struct clk_hw *axg_ao_hw_clks[] = { + [CLKID_AO_REMOTE] = &axg_ao_remote.hw, + [CLKID_AO_I2C_MASTER] = &axg_ao_i2c_master.hw, + [CLKID_AO_I2C_SLAVE] = &axg_ao_i2c_slave.hw, + [CLKID_AO_UART1] = &axg_ao_uart1.hw, + [CLKID_AO_UART2] = &axg_ao_uart2.hw, + [CLKID_AO_IR_BLASTER] = &axg_ao_ir_blaster.hw, + [CLKID_AO_SAR_ADC] = &axg_ao_saradc.hw, + [CLKID_AO_CLK81] = &axg_ao_clk81.hw, + [CLKID_AO_SAR_ADC_SEL] = &axg_ao_saradc_mux.hw, + [CLKID_AO_SAR_ADC_DIV] = &axg_ao_saradc_div.hw, + [CLKID_AO_SAR_ADC_CLK] = &axg_ao_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &axg_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &axg_ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &axg_ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &axg_ao_32k_sel.hw, + [CLKID_AO_32K] = &axg_ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &axg_ao_cts_rtc_oscin.hw, +}; + +static const struct meson_aoclk_data axg_ao_clkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(axg_ao_reset), + .reset = axg_ao_reset, + .clkc_data = { + .hw_clks = { + .hws = axg_ao_hw_clks, + .num = ARRAY_SIZE(axg_ao_hw_clks), + }, + }, +}; + +static const struct of_device_id axg_ao_clkc_match_table[] = { + { + .compatible = "amlogic,meson-axg-aoclkc", + .data = &axg_ao_clkc_data.clkc_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, axg_ao_clkc_match_table); + +static struct platform_driver axg_ao_clkc_driver = { + .probe = meson_aoclkc_probe, + .driver = { + .name = "axg-ao-clkc", + .of_match_table = axg_ao_clkc_match_table, + }, +}; +module_platform_driver(axg_ao_clkc_driver); + +MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c new file mode 100644 index 000000000..fd7eca652 --- /dev/null +++ b/drivers/clk/meson/axg-audio.c @@ -0,0 +1,1448 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meson-clkc-utils.h" +#include "clk-regmap.h" +#include "clk-phase.h" +#include "sclk-div.h" + +#include + +/* Audio clock register offsets */ +#define AUDIO_CLK_GATE_EN 0x000 +#define AUDIO_MCLK_A_CTRL 0x004 +#define AUDIO_MCLK_B_CTRL 0x008 +#define AUDIO_MCLK_C_CTRL 0x00C +#define AUDIO_MCLK_D_CTRL 0x010 +#define AUDIO_MCLK_E_CTRL 0x014 +#define AUDIO_MCLK_F_CTRL 0x018 +#define AUDIO_MST_PAD_CTRL0 0x01c +#define AUDIO_MST_PAD_CTRL1 0x020 +#define AUDIO_SW_RESET 0x024 +#define AUDIO_MST_A_SCLK_CTRL0 0x040 +#define AUDIO_MST_A_SCLK_CTRL1 0x044 +#define AUDIO_MST_B_SCLK_CTRL0 0x048 +#define AUDIO_MST_B_SCLK_CTRL1 0x04C +#define AUDIO_MST_C_SCLK_CTRL0 0x050 +#define AUDIO_MST_C_SCLK_CTRL1 0x054 +#define AUDIO_MST_D_SCLK_CTRL0 0x058 +#define AUDIO_MST_D_SCLK_CTRL1 0x05C +#define AUDIO_MST_E_SCLK_CTRL0 0x060 +#define AUDIO_MST_E_SCLK_CTRL1 0x064 +#define AUDIO_MST_F_SCLK_CTRL0 0x068 +#define AUDIO_MST_F_SCLK_CTRL1 0x06C +#define AUDIO_CLK_TDMIN_A_CTRL 0x080 +#define AUDIO_CLK_TDMIN_B_CTRL 0x084 +#define AUDIO_CLK_TDMIN_C_CTRL 0x088 +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090 +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094 +#define AUDIO_CLK_TDMOUT_C_CTRL 0x098 +#define AUDIO_CLK_SPDIFIN_CTRL 0x09C +#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0 +#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4 +#define AUDIO_CLK_LOCKER_CTRL 0x0A8 +#define AUDIO_CLK_PDMIN_CTRL0 0x0AC +#define AUDIO_CLK_PDMIN_CTRL1 0x0B0 +#define AUDIO_CLK_SPDIFOUT_B_CTRL 0x0B4 + +/* SM1 introduce new register and some shifts :( */ +#define AUDIO_CLK_GATE_EN1 0x004 +#define AUDIO_SM1_MCLK_A_CTRL 0x008 +#define AUDIO_SM1_MCLK_B_CTRL 0x00C +#define AUDIO_SM1_MCLK_C_CTRL 0x010 +#define AUDIO_SM1_MCLK_D_CTRL 0x014 +#define AUDIO_SM1_MCLK_E_CTRL 0x018 +#define AUDIO_SM1_MCLK_F_CTRL 0x01C +#define AUDIO_SM1_MST_PAD_CTRL0 0x020 +#define AUDIO_SM1_MST_PAD_CTRL1 0x024 +#define AUDIO_SM1_SW_RESET0 0x028 +#define AUDIO_SM1_SW_RESET1 0x02C +#define AUDIO_CLK81_CTRL 0x030 +#define AUDIO_CLK81_EN 0x034 +#define AUDIO_EARCRX_CMDC_CLK_CTRL 0x0D0 +#define AUDIO_EARCRX_DMAC_CLK_CTRL 0x0D4 + +#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pdata, _iflags) { \ + .data = &(struct clk_regmap_mux_data){ \ + .offset = (_reg), \ + .mask = (_mask), \ + .shift = (_shift), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_mux_ops, \ + .parent_data = _pdata, \ + .num_parents = ARRAY_SIZE(_pdata), \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) { \ + .data = &(struct clk_regmap_div_data){ \ + .offset = (_reg), \ + .shift = (_shift), \ + .width = (_width), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_divider_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define AUD_PCLK_GATE(_name, _reg, _bit) { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ "aud_top" }, \ + .num_parents = 1, \ + }, \ +} + +#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ + _hi_shift, _hi_width, _pname, _iflags) { \ + .data = &(struct meson_sclk_div_data) { \ + .div = { \ + .reg_off = (_reg), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + }, \ + .hi = { \ + .reg_off = (_reg), \ + .shift = (_hi_shift), \ + .width = (_hi_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_sclk_div_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ + _pname, _iflags) { \ + .data = &(struct meson_clk_triphase_data) { \ + .ph0 = { \ + .reg_off = (_reg), \ + .shift = (_shift0), \ + .width = (_width), \ + }, \ + .ph1 = { \ + .reg_off = (_reg), \ + .shift = (_shift1), \ + .width = (_width), \ + }, \ + .ph2 = { \ + .reg_off = (_reg), \ + .shift = (_shift2), \ + .width = (_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_clk_triphase_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AUD_PHASE(_name, _reg, _width, _shift, _pname, _iflags) { \ + .data = &(struct meson_clk_phase_data) { \ + .ph = { \ + .reg_off = (_reg), \ + .shift = (_shift), \ + .width = (_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_clk_phase_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define AUD_SCLK_WS(_name, _reg, _width, _shift_ph, _shift_ws, _pname, \ + _iflags) { \ + .data = &(struct meson_sclk_ws_inv_data) { \ + .ph = { \ + .reg_off = (_reg), \ + .shift = (_shift_ph), \ + .width = (_width), \ + }, \ + .ws = { \ + .reg_off = (_reg), \ + .shift = (_shift_ws), \ + .width = (_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_clk_phase_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +/* Audio Master Clocks */ +static const struct clk_parent_data mst_mux_parent_data[] = { + { .fw_name = "mst_in0", }, + { .fw_name = "mst_in1", }, + { .fw_name = "mst_in2", }, + { .fw_name = "mst_in3", }, + { .fw_name = "mst_in4", }, + { .fw_name = "mst_in5", }, + { .fw_name = "mst_in6", }, + { .fw_name = "mst_in7", }, +}; + +#define AUD_MST_MUX(_name, _reg, _flag) \ + AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ + mst_mux_parent_data, 0) +#define AUD_MST_DIV(_name, _reg, _flag) \ + AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ + aud_##_name##_sel, CLK_SET_RATE_PARENT) +#define AUD_MST_MCLK_GATE(_name, _reg) \ + AUD_GATE(_name, _reg, 31, aud_##_name##_div, \ + CLK_SET_RATE_PARENT) + +#define AUD_MST_MCLK_MUX(_name, _reg) \ + AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) +#define AUD_MST_MCLK_DIV(_name, _reg) \ + AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) + +#define AUD_MST_SYS_MUX(_name, _reg) \ + AUD_MST_MUX(_name, _reg, 0) +#define AUD_MST_SYS_DIV(_name, _reg) \ + AUD_MST_DIV(_name, _reg, 0) + +/* Sample Clocks */ +#define AUD_MST_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ + aud_mst_##_name##_mclk, 0) +#define AUD_MST_SCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ + aud_mst_##_name##_sclk_pre_en, \ + CLK_SET_RATE_PARENT) +#define AUD_MST_SCLK_POST_EN(_name, _reg) \ + AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ + aud_mst_##_name##_sclk_div, CLK_SET_RATE_PARENT) +#define AUD_MST_SCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ + aud_mst_##_name##_sclk_post_en, CLK_SET_RATE_PARENT) + +#define AUD_MST_LRCLK_DIV(_name, _reg) \ + AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ + aud_mst_##_name##_sclk_post_en, 0) +#define AUD_MST_LRCLK(_name, _reg) \ + AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ + aud_mst_##_name##_lrclk_div, CLK_SET_RATE_PARENT) + +/* TDM bit clock sources */ +static const struct clk_parent_data tdm_sclk_parent_data[] = { + { .name = "aud_mst_a_sclk", .index = -1, }, + { .name = "aud_mst_b_sclk", .index = -1, }, + { .name = "aud_mst_c_sclk", .index = -1, }, + { .name = "aud_mst_d_sclk", .index = -1, }, + { .name = "aud_mst_e_sclk", .index = -1, }, + { .name = "aud_mst_f_sclk", .index = -1, }, + { .fw_name = "slv_sclk0", }, + { .fw_name = "slv_sclk1", }, + { .fw_name = "slv_sclk2", }, + { .fw_name = "slv_sclk3", }, + { .fw_name = "slv_sclk4", }, + { .fw_name = "slv_sclk5", }, + { .fw_name = "slv_sclk6", }, + { .fw_name = "slv_sclk7", }, + { .fw_name = "slv_sclk8", }, + { .fw_name = "slv_sclk9", }, +}; + +/* TDM sample clock sources */ +static const struct clk_parent_data tdm_lrclk_parent_data[] = { + { .name = "aud_mst_a_lrclk", .index = -1, }, + { .name = "aud_mst_b_lrclk", .index = -1, }, + { .name = "aud_mst_c_lrclk", .index = -1, }, + { .name = "aud_mst_d_lrclk", .index = -1, }, + { .name = "aud_mst_e_lrclk", .index = -1, }, + { .name = "aud_mst_f_lrclk", .index = -1, }, + { .fw_name = "slv_lrclk0", }, + { .fw_name = "slv_lrclk1", }, + { .fw_name = "slv_lrclk2", }, + { .fw_name = "slv_lrclk3", }, + { .fw_name = "slv_lrclk4", }, + { .fw_name = "slv_lrclk5", }, + { .fw_name = "slv_lrclk6", }, + { .fw_name = "slv_lrclk7", }, + { .fw_name = "slv_lrclk8", }, + { .fw_name = "slv_lrclk9", }, +}; + +#define AUD_TDM_SCLK_MUX(_name, _reg) \ + AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ + CLK_MUX_ROUND_CLOSEST, tdm_sclk_parent_data, 0) +#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ + aud_tdm##_name##_sclk_sel, CLK_SET_RATE_PARENT) +#define AUD_TDM_SCLK_POST_EN(_name, _reg) \ + AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ + aud_tdm##_name##_sclk_pre_en, CLK_SET_RATE_PARENT) +#define AUD_TDM_SCLK(_name, _reg) \ + AUD_PHASE(tdm##_name##_sclk, _reg, 1, 29, \ + aud_tdm##_name##_sclk_post_en, \ + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT) +#define AUD_TDM_SCLK_WS(_name, _reg) \ + AUD_SCLK_WS(tdm##_name##_sclk, _reg, 1, 29, 28, \ + aud_tdm##_name##_sclk_post_en, \ + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT) + +#define AUD_TDM_LRLCK(_name, _reg) \ + AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ + CLK_MUX_ROUND_CLOSEST, tdm_lrclk_parent_data, 0) + +/* Pad master clock sources */ +static const struct clk_parent_data mclk_pad_ctrl_parent_data[] = { + { .name = "aud_mst_a_mclk", .index = -1, }, + { .name = "aud_mst_b_mclk", .index = -1, }, + { .name = "aud_mst_c_mclk", .index = -1, }, + { .name = "aud_mst_d_mclk", .index = -1, }, + { .name = "aud_mst_e_mclk", .index = -1, }, + { .name = "aud_mst_f_mclk", .index = -1, }, +}; + +/* Pad bit clock sources */ +static const struct clk_parent_data sclk_pad_ctrl_parent_data[] = { + { .name = "aud_mst_a_sclk", .index = -1, }, + { .name = "aud_mst_b_sclk", .index = -1, }, + { .name = "aud_mst_c_sclk", .index = -1, }, + { .name = "aud_mst_d_sclk", .index = -1, }, + { .name = "aud_mst_e_sclk", .index = -1, }, + { .name = "aud_mst_f_sclk", .index = -1, }, +}; + +/* Pad sample clock sources */ +static const struct clk_parent_data lrclk_pad_ctrl_parent_data[] = { + { .name = "aud_mst_a_lrclk", .index = -1, }, + { .name = "aud_mst_b_lrclk", .index = -1, }, + { .name = "aud_mst_c_lrclk", .index = -1, }, + { .name = "aud_mst_d_lrclk", .index = -1, }, + { .name = "aud_mst_e_lrclk", .index = -1, }, + { .name = "aud_mst_f_lrclk", .index = -1, }, +}; + +#define AUD_TDM_PAD_CTRL(_name, _reg, _shift, _parents) \ + AUD_MUX(_name, _reg, 0x7, _shift, 0, _parents, \ + CLK_SET_RATE_NO_REPARENT) + +/* Common Clocks */ +static struct clk_regmap ddr_arb = + AUD_PCLK_GATE(ddr_arb, AUDIO_CLK_GATE_EN, 0); +static struct clk_regmap pdm = + AUD_PCLK_GATE(pdm, AUDIO_CLK_GATE_EN, 1); +static struct clk_regmap tdmin_a = + AUD_PCLK_GATE(tdmin_a, AUDIO_CLK_GATE_EN, 2); +static struct clk_regmap tdmin_b = + AUD_PCLK_GATE(tdmin_b, AUDIO_CLK_GATE_EN, 3); +static struct clk_regmap tdmin_c = + AUD_PCLK_GATE(tdmin_c, AUDIO_CLK_GATE_EN, 4); +static struct clk_regmap tdmin_lb = + AUD_PCLK_GATE(tdmin_lb, AUDIO_CLK_GATE_EN, 5); +static struct clk_regmap tdmout_a = + AUD_PCLK_GATE(tdmout_a, AUDIO_CLK_GATE_EN, 6); +static struct clk_regmap tdmout_b = + AUD_PCLK_GATE(tdmout_b, AUDIO_CLK_GATE_EN, 7); +static struct clk_regmap tdmout_c = + AUD_PCLK_GATE(tdmout_c, AUDIO_CLK_GATE_EN, 8); +static struct clk_regmap frddr_a = + AUD_PCLK_GATE(frddr_a, AUDIO_CLK_GATE_EN, 9); +static struct clk_regmap frddr_b = + AUD_PCLK_GATE(frddr_b, AUDIO_CLK_GATE_EN, 10); +static struct clk_regmap frddr_c = + AUD_PCLK_GATE(frddr_c, AUDIO_CLK_GATE_EN, 11); +static struct clk_regmap toddr_a = + AUD_PCLK_GATE(toddr_a, AUDIO_CLK_GATE_EN, 12); +static struct clk_regmap toddr_b = + AUD_PCLK_GATE(toddr_b, AUDIO_CLK_GATE_EN, 13); +static struct clk_regmap toddr_c = + AUD_PCLK_GATE(toddr_c, AUDIO_CLK_GATE_EN, 14); +static struct clk_regmap loopback = + AUD_PCLK_GATE(loopback, AUDIO_CLK_GATE_EN, 15); +static struct clk_regmap spdifin = + AUD_PCLK_GATE(spdifin, AUDIO_CLK_GATE_EN, 16); +static struct clk_regmap spdifout = + AUD_PCLK_GATE(spdifout, AUDIO_CLK_GATE_EN, 17); +static struct clk_regmap resample = + AUD_PCLK_GATE(resample, AUDIO_CLK_GATE_EN, 18); +static struct clk_regmap power_detect = + AUD_PCLK_GATE(power_detect, AUDIO_CLK_GATE_EN, 19); + +static struct clk_regmap spdifout_clk_sel = + AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static struct clk_regmap pdm_dclk_sel = + AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static struct clk_regmap spdifin_clk_sel = + AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static struct clk_regmap pdm_sysclk_sel = + AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static struct clk_regmap spdifout_b_clk_sel = + AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + +static struct clk_regmap spdifout_clk_div = + AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static struct clk_regmap pdm_dclk_div = + AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static struct clk_regmap spdifin_clk_div = + AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static struct clk_regmap pdm_sysclk_div = + AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static struct clk_regmap spdifout_b_clk_div = + AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + +static struct clk_regmap spdifout_clk = + AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static struct clk_regmap spdifin_clk = + AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static struct clk_regmap pdm_dclk = + AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static struct clk_regmap pdm_sysclk = + AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static struct clk_regmap spdifout_b_clk = + AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + +static struct clk_regmap mst_a_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static struct clk_regmap mst_b_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static struct clk_regmap mst_c_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static struct clk_regmap mst_d_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static struct clk_regmap mst_e_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static struct clk_regmap mst_f_sclk_pre_en = + AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +static struct clk_regmap mst_a_sclk_div = + AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static struct clk_regmap mst_b_sclk_div = + AUD_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static struct clk_regmap mst_c_sclk_div = + AUD_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static struct clk_regmap mst_d_sclk_div = + AUD_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static struct clk_regmap mst_e_sclk_div = + AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static struct clk_regmap mst_f_sclk_div = + AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +static struct clk_regmap mst_a_sclk_post_en = + AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static struct clk_regmap mst_b_sclk_post_en = + AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static struct clk_regmap mst_c_sclk_post_en = + AUD_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static struct clk_regmap mst_d_sclk_post_en = + AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static struct clk_regmap mst_e_sclk_post_en = + AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static struct clk_regmap mst_f_sclk_post_en = + AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +static struct clk_regmap mst_a_sclk = + AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static struct clk_regmap mst_b_sclk = + AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static struct clk_regmap mst_c_sclk = + AUD_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static struct clk_regmap mst_d_sclk = + AUD_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static struct clk_regmap mst_e_sclk = + AUD_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static struct clk_regmap mst_f_sclk = + AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +static struct clk_regmap mst_a_lrclk_div = + AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static struct clk_regmap mst_b_lrclk_div = + AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static struct clk_regmap mst_c_lrclk_div = + AUD_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static struct clk_regmap mst_d_lrclk_div = + AUD_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static struct clk_regmap mst_e_lrclk_div = + AUD_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static struct clk_regmap mst_f_lrclk_div = + AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +static struct clk_regmap mst_a_lrclk = + AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static struct clk_regmap mst_b_lrclk = + AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static struct clk_regmap mst_c_lrclk = + AUD_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static struct clk_regmap mst_d_lrclk = + AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static struct clk_regmap mst_e_lrclk = + AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static struct clk_regmap mst_f_lrclk = + AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +static struct clk_regmap tdmin_a_sclk_sel = + AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static struct clk_regmap tdmin_b_sclk_sel = + AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static struct clk_regmap tdmin_c_sclk_sel = + AUD_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static struct clk_regmap tdmin_lb_sclk_sel = + AUD_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static struct clk_regmap tdmout_a_sclk_sel = + AUD_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap tdmout_b_sclk_sel = + AUD_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap tdmout_c_sclk_sel = + AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +static struct clk_regmap tdmin_a_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static struct clk_regmap tdmin_b_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static struct clk_regmap tdmin_c_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static struct clk_regmap tdmin_lb_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static struct clk_regmap tdmout_a_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap tdmout_b_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap tdmout_c_sclk_pre_en = + AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +static struct clk_regmap tdmin_a_sclk_post_en = + AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static struct clk_regmap tdmin_b_sclk_post_en = + AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static struct clk_regmap tdmin_c_sclk_post_en = + AUD_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static struct clk_regmap tdmin_lb_sclk_post_en = + AUD_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static struct clk_regmap tdmout_a_sclk_post_en = + AUD_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap tdmout_b_sclk_post_en = + AUD_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap tdmout_c_sclk_post_en = + AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +static struct clk_regmap tdmin_a_sclk = + AUD_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static struct clk_regmap tdmin_b_sclk = + AUD_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static struct clk_regmap tdmin_c_sclk = + AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static struct clk_regmap tdmin_lb_sclk = + AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); + +static struct clk_regmap tdmin_a_lrclk = + AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static struct clk_regmap tdmin_b_lrclk = + AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static struct clk_regmap tdmin_c_lrclk = + AUD_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static struct clk_regmap tdmin_lb_lrclk = + AUD_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static struct clk_regmap tdmout_a_lrclk = + AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap tdmout_b_lrclk = + AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap tdmout_c_lrclk = + AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +/* AXG Clocks */ +static struct clk_regmap axg_tdmout_a_sclk = + AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap axg_tdmout_b_sclk = + AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap axg_tdmout_c_sclk = + AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +/* AXG/G12A Clocks */ +static struct clk_hw axg_aud_top = { + .init = &(struct clk_init_data) { + /* Provide aud_top signal name on axg and g12a */ + .name = "aud_top", + .ops = &(const struct clk_ops) {}, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "pclk", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap mst_a_mclk_sel = + AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static struct clk_regmap mst_b_mclk_sel = + AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static struct clk_regmap mst_c_mclk_sel = + AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static struct clk_regmap mst_d_mclk_sel = + AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static struct clk_regmap mst_e_mclk_sel = + AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static struct clk_regmap mst_f_mclk_sel = + AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); + +static struct clk_regmap mst_a_mclk_div = + AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static struct clk_regmap mst_b_mclk_div = + AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static struct clk_regmap mst_c_mclk_div = + AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static struct clk_regmap mst_d_mclk_div = + AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static struct clk_regmap mst_e_mclk_div = + AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static struct clk_regmap mst_f_mclk_div = + AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); + +static struct clk_regmap mst_a_mclk = + AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static struct clk_regmap mst_b_mclk = + AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static struct clk_regmap mst_c_mclk = + AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static struct clk_regmap mst_d_mclk = + AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static struct clk_regmap mst_e_mclk = + AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static struct clk_regmap mst_f_mclk = + AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); + +/* G12a clocks */ +static struct clk_regmap g12a_tdm_mclk_pad_0 = AUD_TDM_PAD_CTRL( + mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, mclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_mclk_pad_1 = AUD_TDM_PAD_CTRL( + mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, mclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_lrclk_pad_0 = AUD_TDM_PAD_CTRL( + lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, lrclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_lrclk_pad_1 = AUD_TDM_PAD_CTRL( + lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, lrclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_lrclk_pad_2 = AUD_TDM_PAD_CTRL( + lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, lrclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_sclk_pad_0 = AUD_TDM_PAD_CTRL( + sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, sclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_sclk_pad_1 = AUD_TDM_PAD_CTRL( + sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, sclk_pad_ctrl_parent_data); +static struct clk_regmap g12a_tdm_sclk_pad_2 = AUD_TDM_PAD_CTRL( + sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, sclk_pad_ctrl_parent_data); + +static struct clk_regmap g12a_tdmout_a_sclk = + AUD_TDM_SCLK_WS(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap g12a_tdmout_b_sclk = + AUD_TDM_SCLK_WS(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap g12a_tdmout_c_sclk = + AUD_TDM_SCLK_WS(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +static struct clk_regmap toram = + AUD_PCLK_GATE(toram, AUDIO_CLK_GATE_EN, 20); +static struct clk_regmap spdifout_b = + AUD_PCLK_GATE(spdifout_b, AUDIO_CLK_GATE_EN, 21); +static struct clk_regmap eqdrc = + AUD_PCLK_GATE(eqdrc, AUDIO_CLK_GATE_EN, 22); + +/* SM1 Clocks */ +static struct clk_regmap sm1_clk81_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = AUDIO_CLK81_EN, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "aud_clk81_en", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "pclk", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap sm1_sysclk_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = AUDIO_CLK81_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "aud_sysclk_a_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_clk81_en.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_sysclk_a_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = AUDIO_CLK81_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "aud_sysclk_a_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_sysclk_a_div.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_sysclk_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = AUDIO_CLK81_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "aud_sysclk_b_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_clk81_en.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_sysclk_b_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = AUDIO_CLK81_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "aud_sysclk_b_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_sysclk_b_div.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *sm1_aud_top_parents[] = { + &sm1_sysclk_a_en.hw, + &sm1_sysclk_b_en.hw, +}; + +static struct clk_regmap sm1_aud_top = { + .data = &(struct clk_regmap_mux_data){ + .offset = AUDIO_CLK81_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "aud_top", + .ops = &clk_regmap_mux_ops, + .parent_hws = sm1_aud_top_parents, + .num_parents = ARRAY_SIZE(sm1_aud_top_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap resample_b = + AUD_PCLK_GATE(resample_b, AUDIO_CLK_GATE_EN, 26); +static struct clk_regmap tovad = + AUD_PCLK_GATE(tovad, AUDIO_CLK_GATE_EN, 27); +static struct clk_regmap locker = + AUD_PCLK_GATE(locker, AUDIO_CLK_GATE_EN, 28); +static struct clk_regmap spdifin_lb = + AUD_PCLK_GATE(spdifin_lb, AUDIO_CLK_GATE_EN, 29); +static struct clk_regmap frddr_d = + AUD_PCLK_GATE(frddr_d, AUDIO_CLK_GATE_EN1, 0); +static struct clk_regmap toddr_d = + AUD_PCLK_GATE(toddr_d, AUDIO_CLK_GATE_EN1, 1); +static struct clk_regmap loopback_b = + AUD_PCLK_GATE(loopback_b, AUDIO_CLK_GATE_EN1, 2); +static struct clk_regmap earcrx = + AUD_PCLK_GATE(earcrx, AUDIO_CLK_GATE_EN1, 6); + + +static struct clk_regmap sm1_mst_a_mclk_sel = + AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); +static struct clk_regmap sm1_mst_b_mclk_sel = + AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_SM1_MCLK_B_CTRL); +static struct clk_regmap sm1_mst_c_mclk_sel = + AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_SM1_MCLK_C_CTRL); +static struct clk_regmap sm1_mst_d_mclk_sel = + AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_SM1_MCLK_D_CTRL); +static struct clk_regmap sm1_mst_e_mclk_sel = + AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); +static struct clk_regmap sm1_mst_f_mclk_sel = + AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk_sel = + AUD_MST_MCLK_MUX(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk_sel = + AUD_MST_MCLK_MUX(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); + +static struct clk_regmap sm1_mst_a_mclk_div = + AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); +static struct clk_regmap sm1_mst_b_mclk_div = + AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_SM1_MCLK_B_CTRL); +static struct clk_regmap sm1_mst_c_mclk_div = + AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_SM1_MCLK_C_CTRL); +static struct clk_regmap sm1_mst_d_mclk_div = + AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_SM1_MCLK_D_CTRL); +static struct clk_regmap sm1_mst_e_mclk_div = + AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); +static struct clk_regmap sm1_mst_f_mclk_div = + AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk_div = + AUD_MST_MCLK_DIV(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk_div = + AUD_MST_MCLK_DIV(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); + + +static struct clk_regmap sm1_mst_a_mclk = + AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); +static struct clk_regmap sm1_mst_b_mclk = + AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_SM1_MCLK_B_CTRL); +static struct clk_regmap sm1_mst_c_mclk = + AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_SM1_MCLK_C_CTRL); +static struct clk_regmap sm1_mst_d_mclk = + AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_SM1_MCLK_D_CTRL); +static struct clk_regmap sm1_mst_e_mclk = + AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); +static struct clk_regmap sm1_mst_f_mclk = + AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk = + AUD_MST_MCLK_GATE(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk = + AUD_MST_MCLK_GATE(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); + +static struct clk_regmap sm1_tdm_mclk_pad_0 = AUD_TDM_PAD_CTRL( + tdm_mclk_pad_0, AUDIO_SM1_MST_PAD_CTRL0, 0, mclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_mclk_pad_1 = AUD_TDM_PAD_CTRL( + tdm_mclk_pad_1, AUDIO_SM1_MST_PAD_CTRL0, 4, mclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_lrclk_pad_0 = AUD_TDM_PAD_CTRL( + tdm_lrclk_pad_0, AUDIO_SM1_MST_PAD_CTRL1, 16, lrclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_lrclk_pad_1 = AUD_TDM_PAD_CTRL( + tdm_lrclk_pad_1, AUDIO_SM1_MST_PAD_CTRL1, 20, lrclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_lrclk_pad_2 = AUD_TDM_PAD_CTRL( + tdm_lrclk_pad_2, AUDIO_SM1_MST_PAD_CTRL1, 24, lrclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_sclk_pad_0 = AUD_TDM_PAD_CTRL( + tdm_sclk_pad_0, AUDIO_SM1_MST_PAD_CTRL1, 0, sclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_sclk_pad_1 = AUD_TDM_PAD_CTRL( + tdm_sclk_pad_1, AUDIO_SM1_MST_PAD_CTRL1, 4, sclk_pad_ctrl_parent_data); +static struct clk_regmap sm1_tdm_sclk_pad_2 = AUD_TDM_PAD_CTRL( + tdm_sclk_pad_2, AUDIO_SM1_MST_PAD_CTRL1, 8, sclk_pad_ctrl_parent_data); + +/* + * Array of all clocks provided by this provider + * The input clocks of the controller will be populated at runtime + */ +static struct clk_hw *axg_audio_hw_clks[] = { + [AUD_CLKID_DDR_ARB] = &ddr_arb.hw, + [AUD_CLKID_PDM] = &pdm.hw, + [AUD_CLKID_TDMIN_A] = &tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &frddr_c.hw, + [AUD_CLKID_TODDR_A] = &toddr_a.hw, + [AUD_CLKID_TODDR_B] = &toddr_b.hw, + [AUD_CLKID_TODDR_C] = &toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &loopback.hw, + [AUD_CLKID_SPDIFIN] = &spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &spdifout.hw, + [AUD_CLKID_RESAMPLE] = &resample.hw, + [AUD_CLKID_POWER_DETECT] = &power_detect.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &spdifout_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &tdmout_c_lrclk.hw, + [AUD_CLKID_TOP] = &axg_aud_top, +}; + +/* + * Array of all G12A clocks provided by this provider + * The input clocks of the controller will be populated at runtime + */ +static struct clk_hw *g12a_audio_hw_clks[] = { + [AUD_CLKID_DDR_ARB] = &ddr_arb.hw, + [AUD_CLKID_PDM] = &pdm.hw, + [AUD_CLKID_TDMIN_A] = &tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &frddr_c.hw, + [AUD_CLKID_TODDR_A] = &toddr_a.hw, + [AUD_CLKID_TODDR_B] = &toddr_b.hw, + [AUD_CLKID_TODDR_C] = &toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &loopback.hw, + [AUD_CLKID_SPDIFIN] = &spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &spdifout.hw, + [AUD_CLKID_RESAMPLE] = &resample.hw, + [AUD_CLKID_POWER_DETECT] = &power_detect.hw, + [AUD_CLKID_SPDIFOUT_B] = &spdifout_b.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &spdifout_clk.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_SEL] = &spdifout_b_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_DIV] = &spdifout_b_clk_div.hw, + [AUD_CLKID_SPDIFOUT_B_CLK] = &spdifout_b_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &tdmout_c_lrclk.hw, + [AUD_CLKID_TDM_MCLK_PAD0] = &g12a_tdm_mclk_pad_0.hw, + [AUD_CLKID_TDM_MCLK_PAD1] = &g12a_tdm_mclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD0] = &g12a_tdm_lrclk_pad_0.hw, + [AUD_CLKID_TDM_LRCLK_PAD1] = &g12a_tdm_lrclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD2] = &g12a_tdm_lrclk_pad_2.hw, + [AUD_CLKID_TDM_SCLK_PAD0] = &g12a_tdm_sclk_pad_0.hw, + [AUD_CLKID_TDM_SCLK_PAD1] = &g12a_tdm_sclk_pad_1.hw, + [AUD_CLKID_TDM_SCLK_PAD2] = &g12a_tdm_sclk_pad_2.hw, + [AUD_CLKID_TOP] = &axg_aud_top, +}; + +/* + * Array of all SM1 clocks provided by this provider + * The input clocks of the controller will be populated at runtime + */ +static struct clk_hw *sm1_audio_hw_clks[] = { + [AUD_CLKID_DDR_ARB] = &ddr_arb.hw, + [AUD_CLKID_PDM] = &pdm.hw, + [AUD_CLKID_TDMIN_A] = &tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &frddr_c.hw, + [AUD_CLKID_TODDR_A] = &toddr_a.hw, + [AUD_CLKID_TODDR_B] = &toddr_b.hw, + [AUD_CLKID_TODDR_C] = &toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &loopback.hw, + [AUD_CLKID_SPDIFIN] = &spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &spdifout.hw, + [AUD_CLKID_RESAMPLE] = &resample.hw, + [AUD_CLKID_SPDIFOUT_B] = &spdifout_b.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &sm1_mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &sm1_mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &sm1_mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &sm1_mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &sm1_mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &sm1_mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &sm1_mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &sm1_mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &sm1_mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &sm1_mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &sm1_mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &sm1_mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &sm1_mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &sm1_mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &sm1_mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &sm1_mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &sm1_mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &sm1_mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &spdifout_clk.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_SEL] = &spdifout_b_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_B_CLK_DIV] = &spdifout_b_clk_div.hw, + [AUD_CLKID_SPDIFOUT_B_CLK] = &spdifout_b_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &tdmout_c_lrclk.hw, + [AUD_CLKID_TDM_MCLK_PAD0] = &sm1_tdm_mclk_pad_0.hw, + [AUD_CLKID_TDM_MCLK_PAD1] = &sm1_tdm_mclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD0] = &sm1_tdm_lrclk_pad_0.hw, + [AUD_CLKID_TDM_LRCLK_PAD1] = &sm1_tdm_lrclk_pad_1.hw, + [AUD_CLKID_TDM_LRCLK_PAD2] = &sm1_tdm_lrclk_pad_2.hw, + [AUD_CLKID_TDM_SCLK_PAD0] = &sm1_tdm_sclk_pad_0.hw, + [AUD_CLKID_TDM_SCLK_PAD1] = &sm1_tdm_sclk_pad_1.hw, + [AUD_CLKID_TDM_SCLK_PAD2] = &sm1_tdm_sclk_pad_2.hw, + [AUD_CLKID_TOP] = &sm1_aud_top.hw, + [AUD_CLKID_TORAM] = &toram.hw, + [AUD_CLKID_EQDRC] = &eqdrc.hw, + [AUD_CLKID_RESAMPLE_B] = &resample_b.hw, + [AUD_CLKID_TOVAD] = &tovad.hw, + [AUD_CLKID_LOCKER] = &locker.hw, + [AUD_CLKID_SPDIFIN_LB] = &spdifin_lb.hw, + [AUD_CLKID_FRDDR_D] = &frddr_d.hw, + [AUD_CLKID_TODDR_D] = &toddr_d.hw, + [AUD_CLKID_LOOPBACK_B] = &loopback_b.hw, + [AUD_CLKID_CLK81_EN] = &sm1_clk81_en.hw, + [AUD_CLKID_SYSCLK_A_DIV] = &sm1_sysclk_a_div.hw, + [AUD_CLKID_SYSCLK_A_EN] = &sm1_sysclk_a_en.hw, + [AUD_CLKID_SYSCLK_B_DIV] = &sm1_sysclk_b_div.hw, + [AUD_CLKID_SYSCLK_B_EN] = &sm1_sysclk_b_en.hw, + [AUD_CLKID_EARCRX] = &earcrx.hw, + [AUD_CLKID_EARCRX_CMDC_SEL] = &sm1_earcrx_cmdc_clk_sel.hw, + [AUD_CLKID_EARCRX_CMDC_DIV] = &sm1_earcrx_cmdc_clk_div.hw, + [AUD_CLKID_EARCRX_CMDC] = &sm1_earcrx_cmdc_clk.hw, + [AUD_CLKID_EARCRX_DMAC_SEL] = &sm1_earcrx_dmac_clk_sel.hw, + [AUD_CLKID_EARCRX_DMAC_DIV] = &sm1_earcrx_dmac_clk_div.hw, + [AUD_CLKID_EARCRX_DMAC] = &sm1_earcrx_dmac_clk.hw, +}; + +static struct regmap_config axg_audio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +struct audioclk_data { + struct meson_clk_hw_data hw_clks; + const char *rst_drvname; + unsigned int max_register; +}; + +static int axg_audio_clkc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct audioclk_data *data; + struct auxiliary_device *auxdev; + struct regmap *map; + void __iomem *regs; + struct clk_hw *hw; + struct clk *clk; + int ret, i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + axg_audio_regmap_cfg.max_register = data->max_register; + map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg); + if (IS_ERR(map)) { + dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map)); + return PTR_ERR(map); + } + + /* Get the mandatory peripheral clock */ + clk = devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = device_reset(dev); + if (ret) { + dev_err_probe(dev, ret, "failed to reset device\n"); + return ret; + } + + /* Take care to skip the registered input clocks */ + for (i = AUD_CLKID_DDR_ARB; i < data->hw_clks.num; i++) { + const char *name; + + hw = data->hw_clks.hws[i]; + /* array might be sparse */ + if (!hw) + continue; + + name = hw->init->name; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "failed to register clock %s\n", name); + return ret; + } + } + + ret = devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); + if (ret) + return ret; + + /* Register auxiliary reset driver when applicable */ + if (data->rst_drvname) { + auxdev = __devm_auxiliary_device_create(dev, dev->driver->name, + data->rst_drvname, NULL, 0); + if (!auxdev) + return -ENODEV; + } + + return 0; +} + +static const struct audioclk_data axg_audioclk_data = { + .hw_clks = { + .hws = axg_audio_hw_clks, + .num = ARRAY_SIZE(axg_audio_hw_clks), + }, + .max_register = AUDIO_CLK_PDMIN_CTRL1, +}; + +static const struct audioclk_data g12a_audioclk_data = { + .hw_clks = { + .hws = g12a_audio_hw_clks, + .num = ARRAY_SIZE(g12a_audio_hw_clks), + }, + .rst_drvname = "rst-g12a", + .max_register = AUDIO_CLK_SPDIFOUT_B_CTRL, +}; + +static const struct audioclk_data sm1_audioclk_data = { + .hw_clks = { + .hws = sm1_audio_hw_clks, + .num = ARRAY_SIZE(sm1_audio_hw_clks), + }, + .rst_drvname = "rst-sm1", + .max_register = AUDIO_EARCRX_DMAC_CLK_CTRL, +}; + +static const struct of_device_id clkc_match_table[] = { + { + .compatible = "amlogic,axg-audio-clkc", + .data = &axg_audioclk_data + }, { + .compatible = "amlogic,g12a-audio-clkc", + .data = &g12a_audioclk_data + }, { + .compatible = "amlogic,sm1-audio-clkc", + .data = &sm1_audioclk_data + }, {} +}; +MODULE_DEVICE_TABLE(of, clkc_match_table); + +static struct platform_driver axg_audio_driver = { + .probe = axg_audio_clkc_probe, + .driver = { + .name = "axg-audio-clkc", + .of_match_table = clkc_match_table, + }, +}; +module_platform_driver(axg_audio_driver); + +MODULE_DESCRIPTION("Amlogic AXG/G12A/SM1 Audio Clock driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c new file mode 100644 index 000000000..280842e9c --- /dev/null +++ b/drivers/clk/meson/axg.c @@ -0,0 +1,2148 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AmLogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2017 Amlogic, inc. + * Author: Qiufang Dai + */ + +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" +#include "meson-clkc-utils.h" + +#include + +#define HHI_GP0_PLL_CNTL 0x40 +#define HHI_GP0_PLL_CNTL2 0x44 +#define HHI_GP0_PLL_CNTL3 0x48 +#define HHI_GP0_PLL_CNTL4 0x4c +#define HHI_GP0_PLL_CNTL5 0x50 +#define HHI_GP0_PLL_STS 0x54 +#define HHI_GP0_PLL_CNTL1 0x58 +#define HHI_HIFI_PLL_CNTL 0x80 +#define HHI_HIFI_PLL_CNTL2 0x84 +#define HHI_HIFI_PLL_CNTL3 0x88 +#define HHI_HIFI_PLL_CNTL4 0x8C +#define HHI_HIFI_PLL_CNTL5 0x90 +#define HHI_HIFI_PLL_STS 0x94 +#define HHI_HIFI_PLL_CNTL1 0x98 + +#define HHI_XTAL_DIVN_CNTL 0xbc +#define HHI_GCLK2_MPEG0 0xc0 +#define HHI_GCLK2_MPEG1 0xc4 +#define HHI_GCLK2_MPEG2 0xc8 +#define HHI_GCLK2_OTHER 0xd0 +#define HHI_GCLK2_AO 0xd4 +#define HHI_PCIE_PLL_CNTL 0xd8 +#define HHI_PCIE_PLL_CNTL1 0xdC +#define HHI_PCIE_PLL_CNTL2 0xe0 +#define HHI_PCIE_PLL_CNTL3 0xe4 +#define HHI_PCIE_PLL_CNTL4 0xe8 +#define HHI_PCIE_PLL_CNTL5 0xec +#define HHI_PCIE_PLL_CNTL6 0xf0 +#define HHI_PCIE_PLL_STS 0xf4 + +#define HHI_MEM_PD_REG0 0x100 +#define HHI_VPU_MEM_PD_REG0 0x104 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12c + +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_AO 0x154 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c +#define HHI_SYS_CPU_RESET_CNTL 0x160 +#define HHI_VID_CLK_DIV 0x164 +#define HHI_SPICC_HCLK_CNTL 0x168 + +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_TS_CLK_CNTL 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_VID_PLL_CLK_DIV 0x1a0 +#define HHI_VPU_CLK_CNTL 0x1bC + +#define HHI_VAPBCLK_CNTL 0x1F4 + +#define HHI_GEN_CLK_CNTL 0x228 + +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 +#define HHI_NAND_CLK_CNTL 0x25C +#define HHI_SD_EMMC_CLK_CNTL 0x264 + +#define HHI_MPLL_CNTL 0x280 +#define HHI_MPLL_CNTL2 0x284 +#define HHI_MPLL_CNTL3 0x288 +#define HHI_MPLL_CNTL4 0x28C +#define HHI_MPLL_CNTL5 0x290 +#define HHI_MPLL_CNTL6 0x294 +#define HHI_MPLL_CNTL7 0x298 +#define HHI_MPLL_CNTL8 0x29C +#define HHI_MPLL_CNTL9 0x2A0 +#define HHI_MPLL_CNTL10 0x2A4 + +#define HHI_MPLL3_CNTL0 0x2E0 +#define HHI_MPLL3_CNTL1 0x2E4 +#define HHI_PLL_TOP_MISC 0x2E8 + +#define HHI_SYS_PLL_CNTL1 0x2FC +#define HHI_SYS_PLL_CNTL 0x300 +#define HHI_SYS_PLL_CNTL2 0x304 +#define HHI_SYS_PLL_CNTL3 0x308 +#define HHI_SYS_PLL_CNTL4 0x30c +#define HHI_SYS_PLL_CNTL5 0x310 +#define HHI_SYS_PLL_STS 0x314 +#define HHI_DPLL_TOP_I 0x318 +#define HHI_DPLL_TOP2_I 0x31C + +static struct clk_regmap axg_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap axg_sys_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_sys_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_params_table axg_gp0_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(67, 1), + PLL_PARAMS(68, 1), + { /* sentinel */ }, +}; + +static const struct reg_sequence axg_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, +}; + +static struct clk_regmap axg_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_params_table, + .init_regs = axg_gp0_init_regs, + .init_count = ARRAY_SIZE(axg_gp0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence axg_hifi_pll_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, +}; + +static struct clk_regmap axg_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL5, + .shift = 0, + .width = 13, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_params_table, + .init_regs = axg_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(axg_hifi_pll_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor axg_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div2_div.hw + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor axg_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div3_div.hw + }, + .num_parents = 1, + /* + * FIXME: + * This clock, as fdiv2, is used by the SCPI FW and is required + * by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) The SCPI generic driver claims and enable all the clocks + * it needs + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor axg_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 0, + .width = 1, + }, + .flags = CLK_MESON_MPLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 1, + .width = 1, + }, + .flags = CLK_MESON_MPLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + .width = 1, + }, + .flags = CLK_MESON_MPLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 12, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 11, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 2, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 3, + .width = 1, + }, + .flags = CLK_MESON_MPLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL3_CNTL0, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_mpll3_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_params_table axg_pcie_pll_params_table[] = { + { + .m = 200, + .n = 3, + }, + { /* sentinel */ }, +}; + +static const struct reg_sequence axg_pcie_pll_init_regs[] = { + { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, + { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, +}; + +static struct clk_regmap axg_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_PCIE_PLL_CNTL1, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_pcie_pll_params_table, + .init_regs = axg_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(axg_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_pcie_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .shift = 6, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_pcie_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .mask = 0x1, + .shift = 2, + /* skip the parent mpll3, reserved for debug */ + .table = (u32[]){ 1 }, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_mux", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_pll.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_ref = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .mask = 0x1, + .shift = 1, + /* skip the parent 0, reserved for debug */ + .table = (u32[]){ 1 }, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_mux.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_cml_en0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + + }, +}; + +static struct clk_regmap axg_pcie_cml_en1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_pcie_ref.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* clk81 is often referred as "mpeg_clk" */ +static u32 clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data clk81_parents[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div7.hw }, + { .hw = &axg_mpll1.hw }, + { .hw = &axg_mpll2.hw }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, +}; + +static struct clk_regmap axg_clk81_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = clk81_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = clk81_parents, + .num_parents = ARRAY_SIZE(clk81_parents), + }, +}; + +static struct clk_regmap axg_clk81_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_clk81_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_clk81_div.hw + }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, +}; + +static const struct clk_parent_data axg_sd_emmc_clk0_parents[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div2.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be achieved using + * xtal or fclk_div clocks + */ +}; + +/* SDcard clock */ +static struct clk_regmap axg_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = axg_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_b_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_b_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_regmap axg_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = axg_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_c_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_sd_emmc_c_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VPU Clock */ + +static const struct clk_hw *axg_vpu_parents[] = { + &axg_fclk_div4.hw, + &axg_fclk_div3.hw, + &axg_fclk_div5.hw, + &axg_fclk_div7.hw, +}; + +static struct clk_regmap axg_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), + /* We need a specific parent for VPU clock source, let it be set in DT */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_0_div.hw }, + .num_parents = 1, + /* + * We want to avoid CCF to disable the VPU clock if + * display has been set by Bootloader + */ + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), + /* We need a specific parent for VPU clock source, let it be set in DT */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vpu_1_div.hw }, + .num_parents = 1, + /* + * We want to avoid CCF to disable the VPU clock if + * display has been set by Bootloader + */ + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vpu_0.hw, + &axg_vpu_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VAPB Clock */ + +static struct clk_regmap axg_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vpu_parents, + .num_parents = ARRAY_SIZE(axg_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vapb_0.hw, + &axg_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap axg_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* Video Clocks */ + +static const struct clk_hw *axg_vclk_parents[] = { + &axg_gp0_pll.hw, + &axg_fclk_div4.hw, + &axg_fclk_div3.hw, + &axg_fclk_div5.hw, + &axg_fclk_div2.hw, + &axg_fclk_div7.hw, + &axg_mpll1.hw, +}; + +static struct clk_regmap axg_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vclk_parents, + .num_parents = ARRAY_SIZE(axg_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_vclk_parents, + .num_parents = ARRAY_SIZE(axg_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap axg_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &axg_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_fixed_factor axg_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vclk2_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static u32 axg_cts_encl_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *axg_cts_encl_parents[] = { + &axg_vclk_div1.hw, + &axg_vclk_div2.hw, + &axg_vclk_div4.hw, + &axg_vclk_div6.hw, + &axg_vclk_div12.hw, + &axg_vclk2_div1.hw, + &axg_vclk2_div2.hw, + &axg_vclk2_div4.hw, + &axg_vclk2_div6.hw, + &axg_vclk2_div12.hw, +}; + +static struct clk_regmap axg_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = axg_cts_encl_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = axg_cts_encl_parents, + .num_parents = ARRAY_SIZE(axg_cts_encl_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap axg_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* MIPI DSI Host Clock */ + +static u32 axg_vdin_meas_parents_val_table[] = { 0, 1, 2, 3, 6, 7 }; +static const struct clk_parent_data axg_vdin_meas_parents[] = { + { .fw_name = "xtal", }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div2.hw }, + { .hw = &axg_fclk_div7.hw }, +}; + +static struct clk_regmap axg_vdin_meas_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .mask = 0x7, + .shift = 21, + .flags = CLK_MUX_ROUND_CLOSEST, + .table = axg_vdin_meas_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = axg_vdin_meas_parents, + .num_parents = ARRAY_SIZE(axg_vdin_meas_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vdin_meas_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .shift = 12, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vdin_meas_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_vdin_meas = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDIN_MEAS_CLK_CNTL, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_vdin_meas_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 gen_clk_parents_val_table[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; +static const struct clk_parent_data gen_clk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &axg_hifi_pll.hw }, + { .hw = &axg_mpll0.hw }, + { .hw = &axg_mpll1.hw }, + { .hw = &axg_mpll2.hw }, + { .hw = &axg_mpll3.hw }, + { .hw = &axg_fclk_div4.hw }, + { .hw = &axg_fclk_div3.hw }, + { .hw = &axg_fclk_div5.hw }, + { .hw = &axg_fclk_div7.hw }, + { .hw = &axg_gp0_pll.hw }, +}; + +static struct clk_regmap axg_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_GEN_CLK_CNTL, + .mask = 0xf, + .shift = 12, + .table = gen_clk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 15:12 selects from 14 possible parents: + * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], + * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ + .parent_data = gen_clk_parents, + .num_parents = ARRAY_SIZE(gen_clk_parents), + }, +}; + +static struct clk_regmap axg_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GEN_CLK_CNTL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_gen_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_GEN_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &axg_gen_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data axg_pclk_parents = { .hw = &axg_clk81.hw }; + +#define AXG_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(axg_##_name, _reg, _bit, &axg_pclk_parents, _flags) + +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static AXG_PCLK(ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(audio_locker, HHI_GCLK_MPEG0, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(mipi_dsi_host, HHI_GCLK_MPEG0, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static AXG_PCLK(pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static AXG_PCLK(periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static AXG_PCLK(spicc_0, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static AXG_PCLK(i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static AXG_PCLK(rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static AXG_PCLK(uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static AXG_PCLK(mipi_dsi_phy, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static AXG_PCLK(spicc_1, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static AXG_PCLK(pcie_a, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static AXG_PCLK(pcie_b, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static AXG_PCLK(hiu_reg, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static AXG_PCLK(assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static AXG_PCLK(emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static AXG_PCLK(emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(dma, HHI_GCLK_MPEG0, 27, CLK_IGNORE_UNUSED); +static AXG_PCLK(spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); + +static AXG_PCLK(audio, HHI_GCLK_MPEG1, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(eth_core, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static AXG_PCLK(g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static AXG_PCLK(reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb_general, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static AXG_PCLK(efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static AXG_PCLK(boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); + +static AXG_PCLK(ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static AXG_PCLK(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb1_to_ddr, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static AXG_PCLK(usb0_to_ddr, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static AXG_PCLK(mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static AXG_PCLK(vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static AXG_PCLK(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static AXG_PCLK(gic, HHI_GCLK_MPEG2, 30, CLK_IGNORE_UNUSED); + +/* Always On (AO) domain gates */ + +static AXG_PCLK(ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); +static AXG_PCLK(ao_i2c, HHI_GCLK_AO, 4, CLK_IGNORE_UNUSED); + +/* Array of all clocks provided by this provider */ + +static struct clk_hw *axg_hw_clks[] = { + [CLKID_SYS_PLL] = &axg_sys_pll.hw, + [CLKID_FIXED_PLL] = &axg_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &axg_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &axg_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &axg_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &axg_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &axg_fclk_div7.hw, + [CLKID_GP0_PLL] = &axg_gp0_pll.hw, + [CLKID_MPEG_SEL] = &axg_clk81_sel.hw, + [CLKID_MPEG_DIV] = &axg_clk81_div.hw, + [CLKID_CLK81] = &axg_clk81.hw, + [CLKID_MPLL0] = &axg_mpll0.hw, + [CLKID_MPLL1] = &axg_mpll1.hw, + [CLKID_MPLL2] = &axg_mpll2.hw, + [CLKID_MPLL3] = &axg_mpll3.hw, + [CLKID_DDR] = &axg_ddr.hw, + [CLKID_AUDIO_LOCKER] = &axg_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &axg_mipi_dsi_host.hw, + [CLKID_ISA] = &axg_isa.hw, + [CLKID_PL301] = &axg_pl301.hw, + [CLKID_PERIPHS] = &axg_periphs.hw, + [CLKID_SPICC0] = &axg_spicc_0.hw, + [CLKID_I2C] = &axg_i2c.hw, + [CLKID_RNG0] = &axg_rng0.hw, + [CLKID_UART0] = &axg_uart0.hw, + [CLKID_MIPI_DSI_PHY] = &axg_mipi_dsi_phy.hw, + [CLKID_SPICC1] = &axg_spicc_1.hw, + [CLKID_PCIE_A] = &axg_pcie_a.hw, + [CLKID_PCIE_B] = &axg_pcie_b.hw, + [CLKID_HIU_IFACE] = &axg_hiu_reg.hw, + [CLKID_ASSIST_MISC] = &axg_assist_misc.hw, + [CLKID_SD_EMMC_B] = &axg_emmc_b.hw, + [CLKID_SD_EMMC_C] = &axg_emmc_c.hw, + [CLKID_DMA] = &axg_dma.hw, + [CLKID_SPI] = &axg_spi.hw, + [CLKID_AUDIO] = &axg_audio.hw, + [CLKID_ETH] = &axg_eth_core.hw, + [CLKID_UART1] = &axg_uart1.hw, + [CLKID_G2D] = &axg_g2d.hw, + [CLKID_USB0] = &axg_usb0.hw, + [CLKID_USB1] = &axg_usb1.hw, + [CLKID_RESET] = &axg_reset.hw, + [CLKID_USB] = &axg_usb_general.hw, + [CLKID_AHB_ARB0] = &axg_ahb_arb0.hw, + [CLKID_EFUSE] = &axg_efuse.hw, + [CLKID_BOOT_ROM] = &axg_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &axg_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &axg_ahb_ctrl_bus.hw, + [CLKID_USB1_DDR_BRIDGE] = &axg_usb1_to_ddr.hw, + [CLKID_USB0_DDR_BRIDGE] = &axg_usb0_to_ddr.hw, + [CLKID_MMC_PCLK] = &axg_mmc_pclk.hw, + [CLKID_VPU_INTR] = &axg_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &axg_sec_ahb_ahb3_bridge.hw, + [CLKID_GIC] = &axg_gic.hw, + [CLKID_AO_MEDIA_CPU] = &axg_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &axg_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &axg_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &axg_ao_iface.hw, + [CLKID_AO_I2C] = &axg_ao_i2c.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &axg_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &axg_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &axg_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &axg_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &axg_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &axg_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, + [CLKID_HIFI_PLL] = &axg_hifi_pll.hw, + [CLKID_MPLL_PREDIV] = &axg_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &axg_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &axg_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, + [CLKID_PCIE_PLL] = &axg_pcie_pll.hw, + [CLKID_PCIE_MUX] = &axg_pcie_mux.hw, + [CLKID_PCIE_REF] = &axg_pcie_ref.hw, + [CLKID_PCIE_CML_EN0] = &axg_pcie_cml_en0.hw, + [CLKID_PCIE_CML_EN1] = &axg_pcie_cml_en1.hw, + [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, + [CLKID_GEN_CLK] = &axg_gen_clk.hw, + [CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw, + [CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw, + [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw, + [CLKID_VPU_0_DIV] = &axg_vpu_0_div.hw, + [CLKID_VPU_0_SEL] = &axg_vpu_0_sel.hw, + [CLKID_VPU_0] = &axg_vpu_0.hw, + [CLKID_VPU_1_DIV] = &axg_vpu_1_div.hw, + [CLKID_VPU_1_SEL] = &axg_vpu_1_sel.hw, + [CLKID_VPU_1] = &axg_vpu_1.hw, + [CLKID_VPU] = &axg_vpu.hw, + [CLKID_VAPB_0_DIV] = &axg_vapb_0_div.hw, + [CLKID_VAPB_0_SEL] = &axg_vapb_0_sel.hw, + [CLKID_VAPB_0] = &axg_vapb_0.hw, + [CLKID_VAPB_1_DIV] = &axg_vapb_1_div.hw, + [CLKID_VAPB_1_SEL] = &axg_vapb_1_sel.hw, + [CLKID_VAPB_1] = &axg_vapb_1.hw, + [CLKID_VAPB_SEL] = &axg_vapb_sel.hw, + [CLKID_VAPB] = &axg_vapb.hw, + [CLKID_VCLK] = &axg_vclk.hw, + [CLKID_VCLK2] = &axg_vclk2.hw, + [CLKID_VCLK_SEL] = &axg_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &axg_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &axg_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &axg_vclk2_input.hw, + [CLKID_VCLK_DIV] = &axg_vclk_div.hw, + [CLKID_VCLK2_DIV] = &axg_vclk2_div.hw, + [CLKID_VCLK_DIV2_EN] = &axg_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &axg_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &axg_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &axg_vclk_div12_en.hw, + [CLKID_VCLK2_DIV2_EN] = &axg_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &axg_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &axg_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &axg_vclk2_div12_en.hw, + [CLKID_VCLK_DIV1] = &axg_vclk_div1.hw, + [CLKID_VCLK_DIV2] = &axg_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &axg_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &axg_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &axg_vclk_div12.hw, + [CLKID_VCLK2_DIV1] = &axg_vclk2_div1.hw, + [CLKID_VCLK2_DIV2] = &axg_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &axg_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &axg_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &axg_vclk2_div12.hw, + [CLKID_CTS_ENCL_SEL] = &axg_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &axg_cts_encl.hw, + [CLKID_VDIN_MEAS_SEL] = &axg_vdin_meas_sel.hw, + [CLKID_VDIN_MEAS_DIV] = &axg_vdin_meas_div.hw, + [CLKID_VDIN_MEAS] = &axg_vdin_meas.hw, +}; + +static const struct meson_clkc_data axg_clkc_data = { + .hw_clks = { + .hws = axg_hw_clks, + .num = ARRAY_SIZE(axg_hw_clks), + }, +}; + +static const struct of_device_id axg_clkc_match_table[] = { + { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, + {} +}; +MODULE_DEVICE_TABLE(of, axg_clkc_match_table); + +static struct platform_driver axg_clkc_driver = { + .probe = meson_clkc_syscon_probe, + .driver = { + .name = "axg-clkc", + .of_match_table = axg_clkc_match_table, + }, +}; +module_platform_driver(axg_clkc_driver); + +MODULE_DESCRIPTION("Amlogic AXG Main Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c new file mode 100644 index 000000000..b158756cf --- /dev/null +++ b/drivers/clk/meson/c3-peripherals.c @@ -0,0 +1,1128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Amlogic C3 Peripherals Clock Controller Driver + * + * Copyright (c) 2023 Amlogic, inc. + * Author: Chuan Liu + */ + +#include +#include +#include "clk-regmap.h" +#include "clk-dualdiv.h" +#include "meson-clkc-utils.h" +#include + +#define RTC_BY_OSCIN_CTRL0 0x8 +#define RTC_BY_OSCIN_CTRL1 0xc +#define RTC_CTRL 0x10 +#define SYS_CLK_EN0_REG0 0x44 +#define SYS_CLK_EN0_REG1 0x48 +#define SYS_CLK_EN0_REG2 0x4c +#define CLK12_24_CTRL 0xa8 +#define AXI_CLK_EN0 0xac +#define VDIN_MEAS_CLK_CTRL 0xf8 +#define VAPB_CLK_CTRL 0xfc +#define MIPIDSI_PHY_CLK_CTRL 0x104 +#define GE2D_CLK_CTRL 0x10c +#define ISP0_CLK_CTRL 0x110 +#define DEWARPA_CLK_CTRL 0x114 +#define VOUTENC_CLK_CTRL 0x118 +#define VDEC_CLK_CTRL 0x140 +#define VDEC3_CLK_CTRL 0x148 +#define TS_CLK_CTRL 0x158 +#define ETH_CLK_CTRL 0x164 +#define NAND_CLK_CTRL 0x168 +#define SD_EMMC_CLK_CTRL 0x16c +#define SPICC_CLK_CTRL 0x174 +#define GEN_CLK_CTRL 0x178 +#define SAR_CLK_CTRL0 0x17c +#define PWM_CLK_AB_CTRL 0x180 +#define PWM_CLK_CD_CTRL 0x184 +#define PWM_CLK_EF_CTRL 0x188 +#define PWM_CLK_GH_CTRL 0x18c +#define PWM_CLK_IJ_CTRL 0x190 +#define PWM_CLK_KL_CTRL 0x194 +#define PWM_CLK_MN_CTRL 0x198 +#define VC9000E_CLK_CTRL 0x19c +#define SPIFC_CLK_CTRL 0x1a0 +#define NNA_CLK_CTRL 0x220 + +#define C3_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(c3_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define C3_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(c3_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define C3_COMP_GATE(_name, _reg, _bit) \ + MESON_COMP_GATE(c3_, _name, _reg, _bit, CLK_SET_RATE_PARENT) + +static struct clk_regmap c3_rtc_xtal_clkin = { + .data = &(struct clk_regmap_gate_data) { + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_xtal_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "oscin", + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param c3_rtc_32k_div_table[] = { + { 733, 732, 8, 11, 1 }, + { /* sentinel */ } +}; + +static struct clk_regmap c3_rtc_32k_div = { + .data = &(struct meson_clk_dualdiv_data) { + .n1 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = c3_rtc_32k_div_table, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_rtc_xtal_clkin.hw + }, + .num_parents = 1, + }, +}; + +static const struct clk_parent_data c3_rtc_32k_parents[] = { + { .hw = &c3_rtc_32k_div.hw }, + { .hw = &c3_rtc_xtal_clkin.hw } +}; + +static struct clk_regmap c3_rtc_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_rtc_32k_parents, + .num_parents = ARRAY_SIZE(c3_rtc_32k_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_rtc_32k = { + .data = &(struct clk_regmap_gate_data) { + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_rtc_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_rtc_clk_parents[] = { + { .fw_name = "oscin" }, + { .hw = &c3_rtc_32k.hw }, + { .fw_name = "pad_osc" } +}; + +static struct clk_regmap c3_rtc_clk = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_CTRL, + .mask = 0x3, + .shift = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_clk", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_rtc_clk_parents, + .num_parents = ARRAY_SIZE(c3_rtc_clk_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_sys_pclk_parents = { .fw_name = "sysclk" }; + +#define C3_SYS_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(c3_##_name, _reg, _bit, &c3_sys_pclk_parents, _flags) + +#define C3_SYS_PCLK_RO(_name, _reg, _bit) \ + MESON_PCLK_RO(c3_##_name, _reg, _bit, &c3_sys_pclk_parents, 0) + +static C3_SYS_PCLK(sys_reset_ctrl, SYS_CLK_EN0_REG0, 1, 0); +static C3_SYS_PCLK(sys_pwr_ctrl, SYS_CLK_EN0_REG0, 3, 0); +static C3_SYS_PCLK(sys_pad_ctrl, SYS_CLK_EN0_REG0, 4, 0); +static C3_SYS_PCLK(sys_ctrl, SYS_CLK_EN0_REG0, 5, 0); +static C3_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG0, 6, 0); + +/* + * NOTE: sys_dev_arb provides the clock to the ETH and SPICC arbiters that + * access the AXI bus. + */ +static C3_SYS_PCLK(sys_dev_arb, SYS_CLK_EN0_REG0, 7, 0); + +/* + * FIXME: sys_mmc_pclk provides the clock for the DDR PHY, DDR will only be + * initialized in bl2, and this clock should not be touched in linux. + */ +static C3_SYS_PCLK_RO(sys_mmc_pclk, SYS_CLK_EN0_REG0, 8); + +/* + * NOTE: sys_cpu_ctrl provides the clock for CPU controller. After clock is + * disabled, cpu_clk and other key CPU-related configurations cannot take effect. + */ +static C3_SYS_PCLK(sys_cpu_ctrl, SYS_CLK_EN0_REG0, 11, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_jtag_ctrl, SYS_CLK_EN0_REG0, 12, 0); +static C3_SYS_PCLK(sys_ir_ctrl, SYS_CLK_EN0_REG0, 13, 0); + +/* + * NOTE: sys_irq_ctrl provides the clock for IRQ controller. The IRQ controller + * collects and distributes the interrupt signal to the GIC, PWR_CTRL, and + * AOCPU. If the clock is disabled, interrupt-related functions will occurs an + * exception. + */ +static C3_SYS_PCLK(sys_irq_ctrl, SYS_CLK_EN0_REG0, 14, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_msr_clk, SYS_CLK_EN0_REG0, 15, 0); +static C3_SYS_PCLK(sys_rom, SYS_CLK_EN0_REG0, 16, 0); +static C3_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG0, 17, 0); +static C3_SYS_PCLK(sys_cpu_apb, SYS_CLK_EN0_REG0, 18, 0); +static C3_SYS_PCLK(sys_rsa, SYS_CLK_EN0_REG0, 19, 0); +static C3_SYS_PCLK(sys_sar_adc, SYS_CLK_EN0_REG0, 20, 0); +static C3_SYS_PCLK(sys_startup, SYS_CLK_EN0_REG0, 21, 0); +static C3_SYS_PCLK(sys_secure, SYS_CLK_EN0_REG0, 22, 0); +static C3_SYS_PCLK(sys_spifc, SYS_CLK_EN0_REG0, 23, 0); +static C3_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 25, 0); +static C3_SYS_PCLK(sys_eth_mac, SYS_CLK_EN0_REG0, 26, 0); + +/* + * FIXME: sys_gic provides the clock for GIC(Generic Interrupt Controller). + * After clock is disabled, The GIC cannot work properly. At present, the driver + * used by our GIC is the public driver in kernel, and there is no management + * clock in the driver. + */ +static C3_SYS_PCLK(sys_gic, SYS_CLK_EN0_REG0, 27, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_rama, SYS_CLK_EN0_REG0, 28, 0); + +/* + * NOTE: sys_big_nic provides the clock to the control bus of the NIC(Network + * Interface Controller) between multiple devices(CPU, DDR, RAM, ROM, GIC, + * SPIFC, CAPU, JTAG, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) in the + * system. After clock is disabled, The NIC cannot work. + */ +static C3_SYS_PCLK(sys_big_nic, SYS_CLK_EN0_REG0, 29, CLK_IS_CRITICAL); +static C3_SYS_PCLK(sys_ramb, SYS_CLK_EN0_REG0, 30, 0); +static C3_SYS_PCLK(sys_audio_pclk, SYS_CLK_EN0_REG0, 31, 0); +static C3_SYS_PCLK(sys_pwm_kl, SYS_CLK_EN0_REG1, 0, 0); +static C3_SYS_PCLK(sys_pwm_ij, SYS_CLK_EN0_REG1, 1, 0); +static C3_SYS_PCLK(sys_usb, SYS_CLK_EN0_REG1, 2, 0); +static C3_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG1, 3, 0); +static C3_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG1, 4, 0); +static C3_SYS_PCLK(sys_pwm_ab, SYS_CLK_EN0_REG1, 5, 0); +static C3_SYS_PCLK(sys_pwm_cd, SYS_CLK_EN0_REG1, 6, 0); +static C3_SYS_PCLK(sys_pwm_ef, SYS_CLK_EN0_REG1, 7, 0); +static C3_SYS_PCLK(sys_pwm_gh, SYS_CLK_EN0_REG1, 8, 0); +static C3_SYS_PCLK(sys_spicc_1, SYS_CLK_EN0_REG1, 9, 0); +static C3_SYS_PCLK(sys_spicc_0, SYS_CLK_EN0_REG1, 10, 0); +static C3_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 11, 0); +static C3_SYS_PCLK(sys_uart_b, SYS_CLK_EN0_REG1, 12, 0); +static C3_SYS_PCLK(sys_uart_c, SYS_CLK_EN0_REG1, 13, 0); +static C3_SYS_PCLK(sys_uart_d, SYS_CLK_EN0_REG1, 14, 0); +static C3_SYS_PCLK(sys_uart_e, SYS_CLK_EN0_REG1, 15, 0); +static C3_SYS_PCLK(sys_i2c_m_a, SYS_CLK_EN0_REG1, 16, 0); +static C3_SYS_PCLK(sys_i2c_m_b, SYS_CLK_EN0_REG1, 17, 0); +static C3_SYS_PCLK(sys_i2c_m_c, SYS_CLK_EN0_REG1, 18, 0); +static C3_SYS_PCLK(sys_i2c_m_d, SYS_CLK_EN0_REG1, 19, 0); +static C3_SYS_PCLK(sys_i2c_s_a, SYS_CLK_EN0_REG1, 20, 0); +static C3_SYS_PCLK(sys_rtc, SYS_CLK_EN0_REG1, 21, 0); +static C3_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 22, 0); +static C3_SYS_PCLK(sys_isp, SYS_CLK_EN0_REG1, 23, 0); +static C3_SYS_PCLK(sys_gpv_isp_nic, SYS_CLK_EN0_REG1, 24, 0); +static C3_SYS_PCLK(sys_gpv_cve_nic, SYS_CLK_EN0_REG1, 25, 0); +static C3_SYS_PCLK(sys_mipi_dsi_host, SYS_CLK_EN0_REG1, 26, 0); +static C3_SYS_PCLK(sys_mipi_dsi_phy, SYS_CLK_EN0_REG1, 27, 0); +static C3_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG1, 28, 0); +static C3_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG1, 29, 0); +static C3_SYS_PCLK(sys_dwap, SYS_CLK_EN0_REG1, 30, 0); +static C3_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG1, 31, 0); +static C3_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG2, 0, 0); +static C3_SYS_PCLK(sys_vout, SYS_CLK_EN0_REG2, 1, 0); +static C3_SYS_PCLK(sys_vc9000e, SYS_CLK_EN0_REG2, 2, 0); +static C3_SYS_PCLK(sys_pwm_mn, SYS_CLK_EN0_REG2, 3, 0); +static C3_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG2, 4, 0); + +static const struct clk_parent_data c3_axi_pclk_parents = { .fw_name = "axiclk" }; + +#define C3_AXI_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(c3_##_name, _reg, _bit, &c3_axi_pclk_parents, _flags) + +/* + * NOTE: axi_sys_nic provides the clock to the AXI bus of the system NIC. After + * clock is disabled, The NIC cannot work. + */ +static C3_AXI_PCLK(axi_sys_nic, AXI_CLK_EN0, 2, CLK_IS_CRITICAL); +static C3_AXI_PCLK(axi_isp_nic, AXI_CLK_EN0, 3, 0); +static C3_AXI_PCLK(axi_cve_nic, AXI_CLK_EN0, 4, 0); +static C3_AXI_PCLK(axi_ramb, AXI_CLK_EN0, 5, 0); +static C3_AXI_PCLK(axi_rama, AXI_CLK_EN0, 6, 0); + +/* + * NOTE: axi_cpu_dmc provides the clock to the AXI bus where the CPU accesses + * the DDR. After clock is disabled, The CPU will not have access to the DDR. + */ +static C3_AXI_PCLK(axi_cpu_dmc, AXI_CLK_EN0, 7, CLK_IS_CRITICAL); +static C3_AXI_PCLK(axi_nic, AXI_CLK_EN0, 8, 0); +static C3_AXI_PCLK(axi_dma, AXI_CLK_EN0, 9, 0); + +/* + * NOTE: axi_mux_nic provides the clock to the NIC's AXI bus for NN(Neural + * Network) and other devices(CPU, EMMC, SDIO, sec_top, USB, Audio, ETH, SPICC) + * to access RAM space. + */ +static C3_AXI_PCLK(axi_mux_nic, AXI_CLK_EN0, 10, 0); +static C3_AXI_PCLK(axi_cve, AXI_CLK_EN0, 12, 0); + +/* + * NOTE: axi_dev1_dmc provides the clock for the peripherals(EMMC, SDIO, + * sec_top, USB, Audio, ETH, SPICC) to access the AXI bus of the DDR. + */ +static C3_AXI_PCLK(axi_dev1_dmc, AXI_CLK_EN0, 13, 0); +static C3_AXI_PCLK(axi_dev0_dmc, AXI_CLK_EN0, 14, 0); +static C3_AXI_PCLK(axi_dsp_dmc, AXI_CLK_EN0, 15, 0); + +/* + * clk_12_24m model + * + * |------| |-----| clk_12m_24m |-----| + * xtal---->| gate |---->| div |------------>| pad | + * |------| |-----| |-----| + */ +static struct clk_regmap c3_clk_12_24m_in = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "clk_12_24m_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal_24m", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_clk_12_24m = { + .data = &(struct clk_regmap_div_data) { + .offset = CLK12_24_CTRL, + .shift = 10, + .width = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "clk_12_24m", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_clk_12_24m_in.hw + }, + .num_parents = 1, + }, +}; + +/* Fix me: set value 0 will div by 2 like value 1 */ +static struct clk_regmap c3_fclk_25m_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLK12_24_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_25m_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_25m = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLK12_24_CTRL, + .bit_idx = 12, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_25m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_25m_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module; channel 12(cts_msr_clk) + * is manged by clock measures module. Their hardware are out of clock tree. + * Channel 4 8 9 10 11 13 14 15 16 18 are not connected. + */ +static u32 c3_gen_parents_val_table[] = { 0, 1, 2, 5, 6, 7, 17, 19, 20, 21, 22, 23, 24}; +static const struct clk_parent_data c3_gen_parents[] = { + { .fw_name = "oscin" }, + { .hw = &c3_rtc_clk.hw }, + { .fw_name = "sysplldiv16" }, + { .fw_name = "gp0" }, + { .fw_name = "gp1" }, + { .fw_name = "hifi" }, + { .fw_name = "cpudiv16" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" } +}; + +static struct clk_regmap c3_gen_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = GEN_CLK_CTRL, + .mask = 0x1f, + .shift = 12, + .table = c3_gen_parents_val_table, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_gen_parents, + .num_parents = ARRAY_SIZE(c3_gen_parents), + }, +}; + +static struct clk_regmap c3_gen_div = { + .data = &(struct clk_regmap_div_data) { + .offset = GEN_CLK_CTRL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_gen_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_gen = { + .data = &(struct clk_regmap_gate_data) { + .offset = GEN_CLK_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_gen_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_saradc_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "sysclk" } +}; + +static C3_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, c3_saradc_parents); +static C3_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8); +static C3_COMP_GATE(saradc, SAR_CLK_CTRL0, 8); + +static const struct clk_parent_data c3_pwm_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "gp1" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv3" } +}; + +static C3_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8); +static C3_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8); + +static C3_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8); +static C3_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24); + +static C3_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8); +static C3_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8); + +static C3_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8); +static C3_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24); + +static C3_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8); +static C3_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8); + +static C3_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8); +static C3_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24); + +static C3_COMP_SEL(pwm_g, PWM_CLK_GH_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_g, PWM_CLK_GH_CTRL, 0, 8); +static C3_COMP_GATE(pwm_g, PWM_CLK_GH_CTRL, 8); + +static C3_COMP_SEL(pwm_h, PWM_CLK_GH_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_h, PWM_CLK_GH_CTRL, 16, 8); +static C3_COMP_GATE(pwm_h, PWM_CLK_GH_CTRL, 24); + +static C3_COMP_SEL(pwm_i, PWM_CLK_IJ_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_i, PWM_CLK_IJ_CTRL, 0, 8); +static C3_COMP_GATE(pwm_i, PWM_CLK_IJ_CTRL, 8); + +static C3_COMP_SEL(pwm_j, PWM_CLK_IJ_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_j, PWM_CLK_IJ_CTRL, 16, 8); +static C3_COMP_GATE(pwm_j, PWM_CLK_IJ_CTRL, 24); + +static C3_COMP_SEL(pwm_k, PWM_CLK_KL_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_k, PWM_CLK_KL_CTRL, 0, 8); +static C3_COMP_GATE(pwm_k, PWM_CLK_KL_CTRL, 8); + +static C3_COMP_SEL(pwm_l, PWM_CLK_KL_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_l, PWM_CLK_KL_CTRL, 16, 8); +static C3_COMP_GATE(pwm_l, PWM_CLK_KL_CTRL, 24); + +static C3_COMP_SEL(pwm_m, PWM_CLK_MN_CTRL, 9, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_m, PWM_CLK_MN_CTRL, 0, 8); +static C3_COMP_GATE(pwm_m, PWM_CLK_MN_CTRL, 8); + +static C3_COMP_SEL(pwm_n, PWM_CLK_MN_CTRL, 25, 0x3, c3_pwm_parents); +static C3_COMP_DIV(pwm_n, PWM_CLK_MN_CTRL, 16, 8); +static C3_COMP_GATE(pwm_n, PWM_CLK_MN_CTRL, 24); + +static const struct clk_parent_data c3_spicc_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "sysclk" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" }, + { .fw_name = "gp1" } +}; + +static C3_COMP_SEL(spicc_a, SPICC_CLK_CTRL, 7, 0x7, c3_spicc_parents); +static C3_COMP_DIV(spicc_a, SPICC_CLK_CTRL, 0, 6); +static C3_COMP_GATE(spicc_a, SPICC_CLK_CTRL, 6); + +static C3_COMP_SEL(spicc_b, SPICC_CLK_CTRL, 23, 0x7, c3_spicc_parents); +static C3_COMP_DIV(spicc_b, SPICC_CLK_CTRL, 16, 6); +static C3_COMP_GATE(spicc_b, SPICC_CLK_CTRL, 22); + +static const struct clk_parent_data c3_spifc_parents[] = { + { .fw_name = "gp0" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "hifi" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(spifc, SPIFC_CLK_CTRL, 9, 0x7, c3_spifc_parents); +static C3_COMP_DIV(spifc, SPIFC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(spifc, SPIFC_CLK_CTRL, 8); + +static const struct clk_parent_data c3_sd_emmc_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv3" }, + { .fw_name = "hifi" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv4" }, + { .fw_name = "gp1" }, + { .fw_name = "gp0" } +}; + +static C3_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7); + +static C3_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7); +static C3_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23); + +static C3_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, c3_sd_emmc_parents); +static C3_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7); +static C3_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7); + +static struct clk_regmap c3_ts_div = { + .data = &(struct clk_regmap_div_data) { + .offset = TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "ts_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "oscin", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_ts = { + .data = &(struct clk_regmap_gate_data) { + .offset = TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_ts_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_eth_parents = { + .fw_name = "fdiv2", +}; + +static struct clk_fixed_factor c3_eth_125m_div = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data) { + .name = "eth_125m_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &c3_eth_parents, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_eth_125m = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "eth_125m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_eth_125m_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_eth_rmii_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ETH_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "eth_rmii_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &c3_eth_parents, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_eth_rmii = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "eth_rmii", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_eth_rmii_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_mipi_dsi_meas_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp1" }, + { .fw_name = "gp0" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 21, 0x7, c3_mipi_dsi_meas_parents); +static C3_COMP_DIV(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 12, 7); +static C3_COMP_GATE(mipi_dsi_meas, VDIN_MEAS_CLK_CTRL, 20); + +static const struct clk_parent_data c3_dsi_phy_parents[] = { + { .fw_name = "gp1" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv2" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 12, 0x7, c3_dsi_phy_parents); +static C3_COMP_DIV(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 0, 7); +static C3_COMP_GATE(dsi_phy, MIPIDSI_PHY_CLK_CTRL, 8); + +static const struct clk_parent_data c3_vout_mclk_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "gp1" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(vout_mclk, VOUTENC_CLK_CTRL, 9, 0x7, c3_vout_mclk_parents); +static C3_COMP_DIV(vout_mclk, VOUTENC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vout_mclk, VOUTENC_CLK_CTRL, 8); + +static const struct clk_parent_data c3_vout_enc_parents[] = { + { .fw_name = "gp1" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(vout_enc, VOUTENC_CLK_CTRL, 25, 0x7, c3_vout_enc_parents); +static C3_COMP_DIV(vout_enc, VOUTENC_CLK_CTRL, 16, 7); +static C3_COMP_GATE(vout_enc, VOUTENC_CLK_CTRL, 24); + +static const struct clk_parent_data c3_hcodec_pre_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" }, + { .fw_name = "hifi" }, + { .fw_name = "gp0" }, + { .fw_name = "oscin" } +}; + +static C3_COMP_SEL(hcodec_0, VDEC_CLK_CTRL, 9, 0x7, c3_hcodec_pre_parents); +static C3_COMP_DIV(hcodec_0, VDEC_CLK_CTRL, 0, 7); +static C3_COMP_GATE(hcodec_0, VDEC_CLK_CTRL, 8); + +static C3_COMP_SEL(hcodec_1, VDEC3_CLK_CTRL, 9, 0x7, c3_hcodec_pre_parents); +static C3_COMP_DIV(hcodec_1, VDEC3_CLK_CTRL, 0, 7); +static C3_COMP_GATE(hcodec_1, VDEC3_CLK_CTRL, 8); + +static const struct clk_parent_data c3_hcodec_parents[] = { + { .hw = &c3_hcodec_0.hw }, + { .hw = &c3_hcodec_1.hw } +}; + +static struct clk_regmap c3_hcodec = { + .data = &(struct clk_regmap_mux_data) { + .offset = VDEC3_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data) { + .name = "hcodec", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_hcodec_parents, + .num_parents = ARRAY_SIZE(c3_hcodec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_vc9000e_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv7" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "hifi" }, + { .fw_name = "gp0" } +}; + +static C3_COMP_SEL(vc9000e_aclk, VC9000E_CLK_CTRL, 9, 0x7, c3_vc9000e_parents); +static C3_COMP_DIV(vc9000e_aclk, VC9000E_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vc9000e_aclk, VC9000E_CLK_CTRL, 8); + +static C3_COMP_SEL(vc9000e_core, VC9000E_CLK_CTRL, 25, 0x7, c3_vc9000e_parents); +static C3_COMP_DIV(vc9000e_core, VC9000E_CLK_CTRL, 16, 7); +static C3_COMP_GATE(vc9000e_core, VC9000E_CLK_CTRL, 24); + +static const struct clk_parent_data c3_csi_phy_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "gp1" }, + { .fw_name = "oscin" } +}; + +static C3_COMP_SEL(csi_phy0, ISP0_CLK_CTRL, 25, 0x7, c3_csi_phy_parents); +static C3_COMP_DIV(csi_phy0, ISP0_CLK_CTRL, 16, 7); +static C3_COMP_GATE(csi_phy0, ISP0_CLK_CTRL, 24); + +static const struct clk_parent_data c3_dewarpa_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "gp1" }, + { .fw_name = "fdiv7" } +}; + +static C3_COMP_SEL(dewarpa, DEWARPA_CLK_CTRL, 9, 0x7, c3_dewarpa_parents); +static C3_COMP_DIV(dewarpa, DEWARPA_CLK_CTRL, 0, 7); +static C3_COMP_GATE(dewarpa, DEWARPA_CLK_CTRL, 8); + +static const struct clk_parent_data c3_isp_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "gp1" }, + { .fw_name = "oscin" } +}; + +static C3_COMP_SEL(isp0, ISP0_CLK_CTRL, 9, 0x7, c3_isp_parents); +static C3_COMP_DIV(isp0, ISP0_CLK_CTRL, 0, 7); +static C3_COMP_GATE(isp0, ISP0_CLK_CTRL, 8); + +static const struct clk_parent_data c3_nna_core_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv5" }, + { .fw_name = "fdiv2" }, + { .fw_name = "gp1" }, + { .fw_name = "hifi" } +}; + +static C3_COMP_SEL(nna_core, NNA_CLK_CTRL, 9, 0x7, c3_nna_core_parents); +static C3_COMP_DIV(nna_core, NNA_CLK_CTRL, 0, 7); +static C3_COMP_GATE(nna_core, NNA_CLK_CTRL, 8); + +static const struct clk_parent_data c3_ge2d_parents[] = { + { .fw_name = "oscin" }, + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "hifi" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .hw = &c3_rtc_clk.hw } +}; + +static C3_COMP_SEL(ge2d, GE2D_CLK_CTRL, 9, 0x7, c3_ge2d_parents); +static C3_COMP_DIV(ge2d, GE2D_CLK_CTRL, 0, 7); +static C3_COMP_GATE(ge2d, GE2D_CLK_CTRL, 8); + +static const struct clk_parent_data c3_vapb_parents[] = { + { .fw_name = "fdiv2p5" }, + { .fw_name = "fdiv3" }, + { .fw_name = "fdiv4" }, + { .fw_name = "fdiv5" }, + { .fw_name = "gp0" }, + { .fw_name = "hifi" }, + { .fw_name = "gp1" }, + { .fw_name = "oscin" }, +}; + +static C3_COMP_SEL(vapb, VAPB_CLK_CTRL, 9, 0x7, c3_vapb_parents); +static C3_COMP_DIV(vapb, VAPB_CLK_CTRL, 0, 7); +static C3_COMP_GATE(vapb, VAPB_CLK_CTRL, 8); + +static struct clk_hw *c3_peripherals_hw_clks[] = { + [CLKID_RTC_XTAL_CLKIN] = &c3_rtc_xtal_clkin.hw, + [CLKID_RTC_32K_DIV] = &c3_rtc_32k_div.hw, + [CLKID_RTC_32K_MUX] = &c3_rtc_32k_sel.hw, + [CLKID_RTC_32K] = &c3_rtc_32k.hw, + [CLKID_RTC_CLK] = &c3_rtc_clk.hw, + [CLKID_SYS_RESET_CTRL] = &c3_sys_reset_ctrl.hw, + [CLKID_SYS_PWR_CTRL] = &c3_sys_pwr_ctrl.hw, + [CLKID_SYS_PAD_CTRL] = &c3_sys_pad_ctrl.hw, + [CLKID_SYS_CTRL] = &c3_sys_ctrl.hw, + [CLKID_SYS_TS_PLL] = &c3_sys_ts_pll.hw, + [CLKID_SYS_DEV_ARB] = &c3_sys_dev_arb.hw, + [CLKID_SYS_MMC_PCLK] = &c3_sys_mmc_pclk.hw, + [CLKID_SYS_CPU_CTRL] = &c3_sys_cpu_ctrl.hw, + [CLKID_SYS_JTAG_CTRL] = &c3_sys_jtag_ctrl.hw, + [CLKID_SYS_IR_CTRL] = &c3_sys_ir_ctrl.hw, + [CLKID_SYS_IRQ_CTRL] = &c3_sys_irq_ctrl.hw, + [CLKID_SYS_MSR_CLK] = &c3_sys_msr_clk.hw, + [CLKID_SYS_ROM] = &c3_sys_rom.hw, + [CLKID_SYS_UART_F] = &c3_sys_uart_f.hw, + [CLKID_SYS_CPU_ARB] = &c3_sys_cpu_apb.hw, + [CLKID_SYS_RSA] = &c3_sys_rsa.hw, + [CLKID_SYS_SAR_ADC] = &c3_sys_sar_adc.hw, + [CLKID_SYS_STARTUP] = &c3_sys_startup.hw, + [CLKID_SYS_SECURE] = &c3_sys_secure.hw, + [CLKID_SYS_SPIFC] = &c3_sys_spifc.hw, + [CLKID_SYS_NNA] = &c3_sys_nna.hw, + [CLKID_SYS_ETH_MAC] = &c3_sys_eth_mac.hw, + [CLKID_SYS_GIC] = &c3_sys_gic.hw, + [CLKID_SYS_RAMA] = &c3_sys_rama.hw, + [CLKID_SYS_BIG_NIC] = &c3_sys_big_nic.hw, + [CLKID_SYS_RAMB] = &c3_sys_ramb.hw, + [CLKID_SYS_AUDIO_PCLK] = &c3_sys_audio_pclk.hw, + [CLKID_SYS_PWM_KL] = &c3_sys_pwm_kl.hw, + [CLKID_SYS_PWM_IJ] = &c3_sys_pwm_ij.hw, + [CLKID_SYS_USB] = &c3_sys_usb.hw, + [CLKID_SYS_SD_EMMC_A] = &c3_sys_sd_emmc_a.hw, + [CLKID_SYS_SD_EMMC_C] = &c3_sys_sd_emmc_c.hw, + [CLKID_SYS_PWM_AB] = &c3_sys_pwm_ab.hw, + [CLKID_SYS_PWM_CD] = &c3_sys_pwm_cd.hw, + [CLKID_SYS_PWM_EF] = &c3_sys_pwm_ef.hw, + [CLKID_SYS_PWM_GH] = &c3_sys_pwm_gh.hw, + [CLKID_SYS_SPICC_1] = &c3_sys_spicc_1.hw, + [CLKID_SYS_SPICC_0] = &c3_sys_spicc_0.hw, + [CLKID_SYS_UART_A] = &c3_sys_uart_a.hw, + [CLKID_SYS_UART_B] = &c3_sys_uart_b.hw, + [CLKID_SYS_UART_C] = &c3_sys_uart_c.hw, + [CLKID_SYS_UART_D] = &c3_sys_uart_d.hw, + [CLKID_SYS_UART_E] = &c3_sys_uart_e.hw, + [CLKID_SYS_I2C_M_A] = &c3_sys_i2c_m_a.hw, + [CLKID_SYS_I2C_M_B] = &c3_sys_i2c_m_b.hw, + [CLKID_SYS_I2C_M_C] = &c3_sys_i2c_m_c.hw, + [CLKID_SYS_I2C_M_D] = &c3_sys_i2c_m_d.hw, + [CLKID_SYS_I2S_S_A] = &c3_sys_i2c_s_a.hw, + [CLKID_SYS_RTC] = &c3_sys_rtc.hw, + [CLKID_SYS_GE2D] = &c3_sys_ge2d.hw, + [CLKID_SYS_ISP] = &c3_sys_isp.hw, + [CLKID_SYS_GPV_ISP_NIC] = &c3_sys_gpv_isp_nic.hw, + [CLKID_SYS_GPV_CVE_NIC] = &c3_sys_gpv_cve_nic.hw, + [CLKID_SYS_MIPI_DSI_HOST] = &c3_sys_mipi_dsi_host.hw, + [CLKID_SYS_MIPI_DSI_PHY] = &c3_sys_mipi_dsi_phy.hw, + [CLKID_SYS_ETH_PHY] = &c3_sys_eth_phy.hw, + [CLKID_SYS_ACODEC] = &c3_sys_acodec.hw, + [CLKID_SYS_DWAP] = &c3_sys_dwap.hw, + [CLKID_SYS_DOS] = &c3_sys_dos.hw, + [CLKID_SYS_CVE] = &c3_sys_cve.hw, + [CLKID_SYS_VOUT] = &c3_sys_vout.hw, + [CLKID_SYS_VC9000E] = &c3_sys_vc9000e.hw, + [CLKID_SYS_PWM_MN] = &c3_sys_pwm_mn.hw, + [CLKID_SYS_SD_EMMC_B] = &c3_sys_sd_emmc_b.hw, + [CLKID_AXI_SYS_NIC] = &c3_axi_sys_nic.hw, + [CLKID_AXI_ISP_NIC] = &c3_axi_isp_nic.hw, + [CLKID_AXI_CVE_NIC] = &c3_axi_cve_nic.hw, + [CLKID_AXI_RAMB] = &c3_axi_ramb.hw, + [CLKID_AXI_RAMA] = &c3_axi_rama.hw, + [CLKID_AXI_CPU_DMC] = &c3_axi_cpu_dmc.hw, + [CLKID_AXI_NIC] = &c3_axi_nic.hw, + [CLKID_AXI_DMA] = &c3_axi_dma.hw, + [CLKID_AXI_MUX_NIC] = &c3_axi_mux_nic.hw, + [CLKID_AXI_CVE] = &c3_axi_cve.hw, + [CLKID_AXI_DEV1_DMC] = &c3_axi_dev1_dmc.hw, + [CLKID_AXI_DEV0_DMC] = &c3_axi_dev0_dmc.hw, + [CLKID_AXI_DSP_DMC] = &c3_axi_dsp_dmc.hw, + [CLKID_12_24M_IN] = &c3_clk_12_24m_in.hw, + [CLKID_12M_24M] = &c3_clk_12_24m.hw, + [CLKID_FCLK_25M_DIV] = &c3_fclk_25m_div.hw, + [CLKID_FCLK_25M] = &c3_fclk_25m.hw, + [CLKID_GEN_SEL] = &c3_gen_sel.hw, + [CLKID_GEN_DIV] = &c3_gen_div.hw, + [CLKID_GEN] = &c3_gen.hw, + [CLKID_SARADC_SEL] = &c3_saradc_sel.hw, + [CLKID_SARADC_DIV] = &c3_saradc_div.hw, + [CLKID_SARADC] = &c3_saradc.hw, + [CLKID_PWM_A_SEL] = &c3_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &c3_pwm_a_div.hw, + [CLKID_PWM_A] = &c3_pwm_a.hw, + [CLKID_PWM_B_SEL] = &c3_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &c3_pwm_b_div.hw, + [CLKID_PWM_B] = &c3_pwm_b.hw, + [CLKID_PWM_C_SEL] = &c3_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &c3_pwm_c_div.hw, + [CLKID_PWM_C] = &c3_pwm_c.hw, + [CLKID_PWM_D_SEL] = &c3_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &c3_pwm_d_div.hw, + [CLKID_PWM_D] = &c3_pwm_d.hw, + [CLKID_PWM_E_SEL] = &c3_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &c3_pwm_e_div.hw, + [CLKID_PWM_E] = &c3_pwm_e.hw, + [CLKID_PWM_F_SEL] = &c3_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &c3_pwm_f_div.hw, + [CLKID_PWM_F] = &c3_pwm_f.hw, + [CLKID_PWM_G_SEL] = &c3_pwm_g_sel.hw, + [CLKID_PWM_G_DIV] = &c3_pwm_g_div.hw, + [CLKID_PWM_G] = &c3_pwm_g.hw, + [CLKID_PWM_H_SEL] = &c3_pwm_h_sel.hw, + [CLKID_PWM_H_DIV] = &c3_pwm_h_div.hw, + [CLKID_PWM_H] = &c3_pwm_h.hw, + [CLKID_PWM_I_SEL] = &c3_pwm_i_sel.hw, + [CLKID_PWM_I_DIV] = &c3_pwm_i_div.hw, + [CLKID_PWM_I] = &c3_pwm_i.hw, + [CLKID_PWM_J_SEL] = &c3_pwm_j_sel.hw, + [CLKID_PWM_J_DIV] = &c3_pwm_j_div.hw, + [CLKID_PWM_J] = &c3_pwm_j.hw, + [CLKID_PWM_K_SEL] = &c3_pwm_k_sel.hw, + [CLKID_PWM_K_DIV] = &c3_pwm_k_div.hw, + [CLKID_PWM_K] = &c3_pwm_k.hw, + [CLKID_PWM_L_SEL] = &c3_pwm_l_sel.hw, + [CLKID_PWM_L_DIV] = &c3_pwm_l_div.hw, + [CLKID_PWM_L] = &c3_pwm_l.hw, + [CLKID_PWM_M_SEL] = &c3_pwm_m_sel.hw, + [CLKID_PWM_M_DIV] = &c3_pwm_m_div.hw, + [CLKID_PWM_M] = &c3_pwm_m.hw, + [CLKID_PWM_N_SEL] = &c3_pwm_n_sel.hw, + [CLKID_PWM_N_DIV] = &c3_pwm_n_div.hw, + [CLKID_PWM_N] = &c3_pwm_n.hw, + [CLKID_SPICC_A_SEL] = &c3_spicc_a_sel.hw, + [CLKID_SPICC_A_DIV] = &c3_spicc_a_div.hw, + [CLKID_SPICC_A] = &c3_spicc_a.hw, + [CLKID_SPICC_B_SEL] = &c3_spicc_b_sel.hw, + [CLKID_SPICC_B_DIV] = &c3_spicc_b_div.hw, + [CLKID_SPICC_B] = &c3_spicc_b.hw, + [CLKID_SPIFC_SEL] = &c3_spifc_sel.hw, + [CLKID_SPIFC_DIV] = &c3_spifc_div.hw, + [CLKID_SPIFC] = &c3_spifc.hw, + [CLKID_SD_EMMC_A_SEL] = &c3_sd_emmc_a_sel.hw, + [CLKID_SD_EMMC_A_DIV] = &c3_sd_emmc_a_div.hw, + [CLKID_SD_EMMC_A] = &c3_sd_emmc_a.hw, + [CLKID_SD_EMMC_B_SEL] = &c3_sd_emmc_b_sel.hw, + [CLKID_SD_EMMC_B_DIV] = &c3_sd_emmc_b_div.hw, + [CLKID_SD_EMMC_B] = &c3_sd_emmc_b.hw, + [CLKID_SD_EMMC_C_SEL] = &c3_sd_emmc_c_sel.hw, + [CLKID_SD_EMMC_C_DIV] = &c3_sd_emmc_c_div.hw, + [CLKID_SD_EMMC_C] = &c3_sd_emmc_c.hw, + [CLKID_TS_DIV] = &c3_ts_div.hw, + [CLKID_TS] = &c3_ts.hw, + [CLKID_ETH_125M_DIV] = &c3_eth_125m_div.hw, + [CLKID_ETH_125M] = &c3_eth_125m.hw, + [CLKID_ETH_RMII_DIV] = &c3_eth_rmii_div.hw, + [CLKID_ETH_RMII] = &c3_eth_rmii.hw, + [CLKID_MIPI_DSI_MEAS_SEL] = &c3_mipi_dsi_meas_sel.hw, + [CLKID_MIPI_DSI_MEAS_DIV] = &c3_mipi_dsi_meas_div.hw, + [CLKID_MIPI_DSI_MEAS] = &c3_mipi_dsi_meas.hw, + [CLKID_DSI_PHY_SEL] = &c3_dsi_phy_sel.hw, + [CLKID_DSI_PHY_DIV] = &c3_dsi_phy_div.hw, + [CLKID_DSI_PHY] = &c3_dsi_phy.hw, + [CLKID_VOUT_MCLK_SEL] = &c3_vout_mclk_sel.hw, + [CLKID_VOUT_MCLK_DIV] = &c3_vout_mclk_div.hw, + [CLKID_VOUT_MCLK] = &c3_vout_mclk.hw, + [CLKID_VOUT_ENC_SEL] = &c3_vout_enc_sel.hw, + [CLKID_VOUT_ENC_DIV] = &c3_vout_enc_div.hw, + [CLKID_VOUT_ENC] = &c3_vout_enc.hw, + [CLKID_HCODEC_0_SEL] = &c3_hcodec_0_sel.hw, + [CLKID_HCODEC_0_DIV] = &c3_hcodec_0_div.hw, + [CLKID_HCODEC_0] = &c3_hcodec_0.hw, + [CLKID_HCODEC_1_SEL] = &c3_hcodec_1_sel.hw, + [CLKID_HCODEC_1_DIV] = &c3_hcodec_1_div.hw, + [CLKID_HCODEC_1] = &c3_hcodec_1.hw, + [CLKID_HCODEC] = &c3_hcodec.hw, + [CLKID_VC9000E_ACLK_SEL] = &c3_vc9000e_aclk_sel.hw, + [CLKID_VC9000E_ACLK_DIV] = &c3_vc9000e_aclk_div.hw, + [CLKID_VC9000E_ACLK] = &c3_vc9000e_aclk.hw, + [CLKID_VC9000E_CORE_SEL] = &c3_vc9000e_core_sel.hw, + [CLKID_VC9000E_CORE_DIV] = &c3_vc9000e_core_div.hw, + [CLKID_VC9000E_CORE] = &c3_vc9000e_core.hw, + [CLKID_CSI_PHY0_SEL] = &c3_csi_phy0_sel.hw, + [CLKID_CSI_PHY0_DIV] = &c3_csi_phy0_div.hw, + [CLKID_CSI_PHY0] = &c3_csi_phy0.hw, + [CLKID_DEWARPA_SEL] = &c3_dewarpa_sel.hw, + [CLKID_DEWARPA_DIV] = &c3_dewarpa_div.hw, + [CLKID_DEWARPA] = &c3_dewarpa.hw, + [CLKID_ISP0_SEL] = &c3_isp0_sel.hw, + [CLKID_ISP0_DIV] = &c3_isp0_div.hw, + [CLKID_ISP0] = &c3_isp0.hw, + [CLKID_NNA_CORE_SEL] = &c3_nna_core_sel.hw, + [CLKID_NNA_CORE_DIV] = &c3_nna_core_div.hw, + [CLKID_NNA_CORE] = &c3_nna_core.hw, + [CLKID_GE2D_SEL] = &c3_ge2d_sel.hw, + [CLKID_GE2D_DIV] = &c3_ge2d_div.hw, + [CLKID_GE2D] = &c3_ge2d.hw, + [CLKID_VAPB_SEL] = &c3_vapb_sel.hw, + [CLKID_VAPB_DIV] = &c3_vapb_div.hw, + [CLKID_VAPB] = &c3_vapb.hw, +}; + +static const struct meson_clkc_data c3_peripherals_clkc_data = { + .hw_clks = { + .hws = c3_peripherals_hw_clks, + .num = ARRAY_SIZE(c3_peripherals_hw_clks), + }, +}; + +static const struct of_device_id c3_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,c3-peripherals-clkc", + .data = &c3_peripherals_clkc_data, + }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, c3_peripherals_clkc_match_table); + +static struct platform_driver c3_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "c3-peripherals-clkc", + .of_match_table = c3_peripherals_clkc_match_table, + }, +}; +module_platform_driver(c3_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic C3 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Chuan Liu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/c3-pll.c b/drivers/clk/meson/c3-pll.c new file mode 100644 index 000000000..dd047d174 --- /dev/null +++ b/drivers/clk/meson/c3-pll.c @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Amlogic C3 PLL Controller Driver + * + * Copyright (c) 2023 Amlogic, inc. + * Author: Chuan Liu + */ + +#include +#include +#include "clk-regmap.h" +#include "clk-pll.h" +#include "meson-clkc-utils.h" +#include + +#define ANACTRL_FIXPLL_CTRL4 0x50 +#define ANACTRL_GP0PLL_CTRL0 0x80 +#define ANACTRL_GP0PLL_CTRL1 0x84 +#define ANACTRL_GP0PLL_CTRL2 0x88 +#define ANACTRL_GP0PLL_CTRL3 0x8c +#define ANACTRL_GP0PLL_CTRL4 0x90 +#define ANACTRL_GP0PLL_CTRL5 0x94 +#define ANACTRL_GP0PLL_CTRL6 0x98 +#define ANACTRL_HIFIPLL_CTRL0 0x100 +#define ANACTRL_HIFIPLL_CTRL1 0x104 +#define ANACTRL_HIFIPLL_CTRL2 0x108 +#define ANACTRL_HIFIPLL_CTRL3 0x10c +#define ANACTRL_HIFIPLL_CTRL4 0x110 +#define ANACTRL_HIFIPLL_CTRL5 0x114 +#define ANACTRL_HIFIPLL_CTRL6 0x118 +#define ANACTRL_MPLL_CTRL0 0x180 +#define ANACTRL_MPLL_CTRL1 0x184 +#define ANACTRL_MPLL_CTRL2 0x188 +#define ANACTRL_MPLL_CTRL3 0x18c +#define ANACTRL_MPLL_CTRL4 0x190 + +static struct clk_regmap c3_fclk_50m_en = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_50m_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_50m = { + .mult = 1, + .div = 40, + .hw.init = &(struct clk_init_data) { + .name = "fclk_50m", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_50m_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div2 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div2", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div2_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div2p5_div = { + .mult = 2, + .div = 5, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div2p5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div3 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div3", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div3_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div4 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div4", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div5 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor c3_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix" + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_fclk_div7 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_FIXPLL_CTRL4, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data) { + .name = "fclk_div7", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static const struct reg_sequence c3_gp0_pll_init_regs[] = { + { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x0 }, + { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, + { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 }, + { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x3927200a }, + { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 }, +}; + +static const struct pll_mult_range c3_gp0_pll_mult_range = { + .min = 125, + .max = 250, +}; + +static struct clk_regmap c3_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data) { + .en = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 0, + .width = 9, + }, + .frac = { + .reg_off = ANACTRL_GP0PLL_CTRL1, + .shift = 0, + .width = 19, + }, + .n = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &c3_gp0_pll_mult_range, + .init_regs = c3_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(c3_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data) { + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "top", + }, + .num_parents = 1, + }, +}; + +/* The maximum frequency divider supports is 32, not 128(2^7) */ +static const struct clk_div_table c3_gp0_pll_od_table[] = { + { 0, 1 }, + { 1, 2 }, + { 2, 4 }, + { 3, 8 }, + { 4, 16 }, + { 5, 32 }, + { /* sentinel */ } +}; + +static struct clk_regmap c3_gp0_pll = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_GP0PLL_CTRL0, + .shift = 16, + .width = 3, + .table = c3_gp0_pll_od_table, + }, + .hw.init = &(struct clk_init_data) { + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence c3_hifi_pll_init_regs[] = { + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x0 }, + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x3927200a }, + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 }, +}; + +static struct clk_regmap c3_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data) { + .en = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .frac = { + .reg_off = ANACTRL_HIFIPLL_CTRL1, + .shift = 0, + .width = 19, + }, + .n = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &c3_gp0_pll_mult_range, + .init_regs = c3_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(c3_hifi_pll_init_regs), + .frac_max = 100000, + }, + .hw.init = &(struct clk_init_data) { + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "top", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap c3_hifi_pll = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_HIFIPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data) { + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence c3_mclk_pll_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL1, .def = 0x1420500f }, + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023041 }, + { .reg = ANACTRL_MPLL_CTRL3, .def = 0x18180000 }, + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x00023001 } +}; + +static const struct pll_mult_range c3_mclk_pll_mult_range = { + .min = 67, + .max = 133, +}; + +static struct clk_regmap c3_mclk_pll_dco = { + .data = &(struct meson_clk_pll_data) { + .en = { + .reg_off = ANACTRL_MPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_MPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_MPLL_CTRL0, + .shift = 16, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_MPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_MPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &c3_mclk_pll_mult_range, + .init_regs = c3_mclk_pll_init_regs, + .init_count = ARRAY_SIZE(c3_mclk_pll_init_regs), + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "mclk", + }, + .num_parents = 1, + }, +}; + +static const struct clk_div_table c3_mpll_pll_od_table[] = { + { 0, 1 }, + { 1, 2 }, + { 2, 4 }, + { 3, 8 }, + { 4, 16 }, + { /* sentinel */ } +}; + +static struct clk_regmap c3_mclk_pll_od = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_MPLL_CTRL0, + .shift = 12, + .width = 3, + .table = c3_mpll_pll_od_table, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk_pll_dco.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* both value 0 and 1 gives divide the input rate by one */ +static struct clk_regmap c3_mclk_pll = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_MPLL_CTRL4, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data c3_mclk_parents[] = { + { .hw = &c3_mclk_pll.hw }, + { .fw_name = "mclk" }, + { .hw = &c3_fclk_50m.hw } +}; + +static struct clk_regmap c3_mclk0_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = ANACTRL_MPLL_CTRL4, + .mask = 0x3, + .shift = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_mclk_parents, + .num_parents = ARRAY_SIZE(c3_mclk_parents), + }, +}; + +static struct clk_regmap c3_mclk0_div_en = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_MPLL_CTRL4, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk0_div_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_mclk0_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_MPLL_CTRL4, + .shift = 2, + .width = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk0_div_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_mclk0 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_MPLL_CTRL4, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_mclk1_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = ANACTRL_MPLL_CTRL4, + .mask = 0x3, + .shift = 12, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = c3_mclk_parents, + .num_parents = ARRAY_SIZE(c3_mclk_parents), + }, +}; + +static struct clk_regmap c3_mclk1_div_en = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_MPLL_CTRL4, + .bit_idx = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk1_div_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_mclk1_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ANACTRL_MPLL_CTRL4, + .shift = 10, + .width = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk1_div_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap c3_mclk1 = { + .data = &(struct clk_regmap_gate_data) { + .offset = ANACTRL_MPLL_CTRL4, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &c3_mclk1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_hw *c3_pll_hw_clks[] = { + [CLKID_FCLK_50M_EN] = &c3_fclk_50m_en.hw, + [CLKID_FCLK_50M] = &c3_fclk_50m.hw, + [CLKID_FCLK_DIV2_DIV] = &c3_fclk_div2_div.hw, + [CLKID_FCLK_DIV2] = &c3_fclk_div2.hw, + [CLKID_FCLK_DIV2P5_DIV] = &c3_fclk_div2p5_div.hw, + [CLKID_FCLK_DIV2P5] = &c3_fclk_div2p5.hw, + [CLKID_FCLK_DIV3_DIV] = &c3_fclk_div3_div.hw, + [CLKID_FCLK_DIV3] = &c3_fclk_div3.hw, + [CLKID_FCLK_DIV4_DIV] = &c3_fclk_div4_div.hw, + [CLKID_FCLK_DIV4] = &c3_fclk_div4.hw, + [CLKID_FCLK_DIV5_DIV] = &c3_fclk_div5_div.hw, + [CLKID_FCLK_DIV5] = &c3_fclk_div5.hw, + [CLKID_FCLK_DIV7_DIV] = &c3_fclk_div7_div.hw, + [CLKID_FCLK_DIV7] = &c3_fclk_div7.hw, + [CLKID_GP0_PLL_DCO] = &c3_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &c3_gp0_pll.hw, + [CLKID_HIFI_PLL_DCO] = &c3_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &c3_hifi_pll.hw, + [CLKID_MCLK_PLL_DCO] = &c3_mclk_pll_dco.hw, + [CLKID_MCLK_PLL_OD] = &c3_mclk_pll_od.hw, + [CLKID_MCLK_PLL] = &c3_mclk_pll.hw, + [CLKID_MCLK0_SEL] = &c3_mclk0_sel.hw, + [CLKID_MCLK0_SEL_EN] = &c3_mclk0_div_en.hw, + [CLKID_MCLK0_DIV] = &c3_mclk0_div.hw, + [CLKID_MCLK0] = &c3_mclk0.hw, + [CLKID_MCLK1_SEL] = &c3_mclk1_sel.hw, + [CLKID_MCLK1_SEL_EN] = &c3_mclk1_div_en.hw, + [CLKID_MCLK1_DIV] = &c3_mclk1_div.hw, + [CLKID_MCLK1] = &c3_mclk1.hw +}; + +static const struct meson_clkc_data c3_pll_clkc_data = { + .hw_clks = { + .hws = c3_pll_hw_clks, + .num = ARRAY_SIZE(c3_pll_hw_clks), + }, +}; + +static const struct of_device_id c3_pll_clkc_match_table[] = { + { + .compatible = "amlogic,c3-pll-clkc", + .data = &c3_pll_clkc_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, c3_pll_clkc_match_table); + +static struct platform_driver c3_pll_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "c3-pll-clkc", + .of_match_table = c3_pll_clkc_match_table, + }, +}; +module_platform_driver(c3_pll_clkc_driver); + +MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); +MODULE_AUTHOR("Chuan Liu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c new file mode 100644 index 000000000..83aedbfd2 --- /dev/null +++ b/drivers/clk/meson/clk-cpu-dyndiv.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#include +#include + +#include "clk-regmap.h" +#include "clk-cpu-dyndiv.h" + +static inline struct meson_clk_cpu_dyndiv_data * +meson_clk_cpu_dyndiv_data(struct clk_regmap *clk) +{ + return (struct meson_clk_cpu_dyndiv_data *)clk->data; +} + +static unsigned long meson_clk_cpu_dyndiv_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + + return divider_recalc_rate(hw, prate, + meson_parm_read(clk->map, &data->div), + NULL, 0, data->div.width); +} + +static int meson_clk_cpu_dyndiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + + return divider_determine_rate(hw, req, NULL, data->div.width, 0); +} + +static int meson_clk_cpu_dyndiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, NULL, data->div.width, 0); + if (ret < 0) + return ret; + + val = (unsigned int)ret << data->div.shift; + + /* Write the SYS_CPU_DYN_ENABLE bit before changing the divider */ + meson_parm_write(clk->map, &data->dyn, 1); + + /* Update the divider while removing the SYS_CPU_DYN_ENABLE bit */ + return regmap_update_bits(clk->map, data->div.reg_off, + SETPMASK(data->div.width, data->div.shift) | + SETPMASK(data->dyn.width, data->dyn.shift), + val); +}; + +const struct clk_ops meson_clk_cpu_dyndiv_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_clk_cpu_dyndiv_recalc_rate, + .determine_rate = meson_clk_cpu_dyndiv_determine_rate, + .set_rate = meson_clk_cpu_dyndiv_set_rate, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_cpu_dyndiv_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.h b/drivers/clk/meson/clk-cpu-dyndiv.h new file mode 100644 index 000000000..f49084047 --- /dev/null +++ b/drivers/clk/meson/clk-cpu-dyndiv.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#ifndef __MESON_CLK_CPU_DYNDIV_H +#define __MESON_CLK_CPU_DYNDIV_H + +#include +#include "parm.h" + +struct meson_clk_cpu_dyndiv_data { + struct parm div; + struct parm dyn; +}; + +extern const struct clk_ops meson_clk_cpu_dyndiv_ops; + +#endif /* __MESON_CLK_CPU_DYNDIV_H */ diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c new file mode 100644 index 000000000..787df6cdf --- /dev/null +++ b/drivers/clk/meson/clk-dualdiv.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 BayLibre, SAS + * Author: Neil Armstrong + * Author: Jerome Brunet + */ + +/* + * The AO Domain embeds a dual/divider to generate a more precise + * 32,768KHz clock for low-power suspend mode and CEC. + * ______ ______ + * | | | | + * | Div1 |-| Cnt1 | + * /|______| |______|\ + * -| ______ ______ X--> Out + * \| | | |/ + * | Div2 |-| Cnt2 | + * |______| |______| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + */ + +#include +#include + +#include "clk-regmap.h" +#include "clk-dualdiv.h" + +static inline struct meson_clk_dualdiv_data * +meson_clk_dualdiv_data(struct clk_regmap *clk) +{ + return (struct meson_clk_dualdiv_data *)clk->data; +} + +static unsigned long +__dualdiv_param_to_rate(unsigned long parent_rate, + const struct meson_clk_dualdiv_param *p) +{ + if (!p->dual) + return DIV_ROUND_CLOSEST(parent_rate, p->n1); + + return DIV_ROUND_CLOSEST(parent_rate * (p->m1 + p->m2), + p->n1 * p->m1 + p->n2 * p->m2); +} + +static unsigned long meson_clk_dualdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + struct meson_clk_dualdiv_param setting; + + setting.dual = meson_parm_read(clk->map, &dualdiv->dual); + setting.n1 = meson_parm_read(clk->map, &dualdiv->n1) + 1; + setting.m1 = meson_parm_read(clk->map, &dualdiv->m1) + 1; + setting.n2 = meson_parm_read(clk->map, &dualdiv->n2) + 1; + setting.m2 = meson_parm_read(clk->map, &dualdiv->m2) + 1; + + return __dualdiv_param_to_rate(parent_rate, &setting); +} + +static const struct meson_clk_dualdiv_param * +__dualdiv_get_setting(unsigned long rate, unsigned long parent_rate, + struct meson_clk_dualdiv_data *dualdiv) +{ + const struct meson_clk_dualdiv_param *table = dualdiv->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + if (!table) + return NULL; + + for (i = 0; table[i].n1; i++) { + now = __dualdiv_param_to_rate(parent_rate, &table[i]); + + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + return (struct meson_clk_dualdiv_param *)&table[best_i]; +} + +static int meson_clk_dualdiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting; + + setting = __dualdiv_get_setting(req->rate, req->best_parent_rate, + dualdiv); + if (setting) + req->rate = __dualdiv_param_to_rate(req->best_parent_rate, + setting); + else + req->rate = meson_clk_dualdiv_recalc_rate(hw, + req->best_parent_rate); + + return 0; +} + +static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting = + __dualdiv_get_setting(rate, parent_rate, dualdiv); + + if (!setting) + return -EINVAL; + + meson_parm_write(clk->map, &dualdiv->dual, setting->dual); + meson_parm_write(clk->map, &dualdiv->n1, setting->n1 - 1); + meson_parm_write(clk->map, &dualdiv->m1, setting->m1 - 1); + meson_parm_write(clk->map, &dualdiv->n2, setting->n2 - 1); + meson_parm_write(clk->map, &dualdiv->m2, setting->m2 - 1); + + return 0; +} + +const struct clk_ops meson_clk_dualdiv_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_clk_dualdiv_recalc_rate, + .determine_rate = meson_clk_dualdiv_determine_rate, + .set_rate = meson_clk_dualdiv_set_rate, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ops, "CLK_MESON"); + +const struct clk_ops meson_clk_dualdiv_ro_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_clk_dualdiv_recalc_rate, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ro_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic dual divider driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-dualdiv.h b/drivers/clk/meson/clk-dualdiv.h new file mode 100644 index 000000000..4aa939018 --- /dev/null +++ b/drivers/clk/meson/clk-dualdiv.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_DUALDIV_H +#define __MESON_CLK_DUALDIV_H + +#include +#include "parm.h" + +struct meson_clk_dualdiv_param { + unsigned int n1; + unsigned int n2; + unsigned int m1; + unsigned int m2; + unsigned int dual; +}; + +struct meson_clk_dualdiv_data { + struct parm n1; + struct parm n2; + struct parm m1; + struct parm m2; + struct parm dual; + const struct meson_clk_dualdiv_param *table; +}; + +extern const struct clk_ops meson_clk_dualdiv_ops; +extern const struct clk_ops meson_clk_dualdiv_ro_ops; + +#endif /* __MESON_CLK_DUALDIV_H */ diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c new file mode 100644 index 000000000..7f8dada66 --- /dev/null +++ b/drivers/clk/meson/clk-mpll.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright (c) 2016 AmLogic, Inc. + * Author: Michael Turquette + */ + +/* + * MultiPhase Locked Loops are outputs from a PLL with additional frequency + * scaling capabilities. MPLL rates are calculated as: + * + * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) + */ + +#include +#include +#include + +#include "clk-regmap.h" +#include "clk-mpll.h" + +#define SDM_DEN 16384 +#define N2_MIN 4 +#define N2_MAX 511 + +static inline struct meson_clk_mpll_data * +meson_clk_mpll_data(struct clk_regmap *clk) +{ + return (struct meson_clk_mpll_data *)clk->data; +} + +static long rate_from_params(unsigned long parent_rate, + unsigned int sdm, + unsigned int n2) +{ + unsigned long divisor = (SDM_DEN * n2) + sdm; + + if (n2 < N2_MIN) + return -EINVAL; + + return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); +} + +static void params_from_rate(unsigned long requested_rate, + unsigned long parent_rate, + unsigned int *sdm, + unsigned int *n2, + u8 flags) +{ + uint64_t div = parent_rate; + uint64_t frac = do_div(div, requested_rate); + + frac *= SDM_DEN; + + if (flags & CLK_MESON_MPLL_ROUND_CLOSEST) + *sdm = DIV_ROUND_CLOSEST_ULL(frac, requested_rate); + else + *sdm = DIV_ROUND_UP_ULL(frac, requested_rate); + + if (*sdm == SDM_DEN) { + *sdm = 0; + div += 1; + } + + if (div < N2_MIN) { + *n2 = N2_MIN; + *sdm = 0; + } else if (div > N2_MAX) { + *n2 = N2_MAX; + *sdm = SDM_DEN - 1; + } else { + *n2 = div; + } +} + +static unsigned long mpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; + long rate; + + sdm = meson_parm_read(clk->map, &mpll->sdm); + n2 = meson_parm_read(clk->map, &mpll->n2); + + rate = rate_from_params(parent_rate, sdm, n2); + return rate < 0 ? 0 : rate; +} + +static int mpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; + long rate; + + params_from_rate(req->rate, req->best_parent_rate, &sdm, &n2, + mpll->flags); + + rate = rate_from_params(req->best_parent_rate, sdm, n2); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; +} + +static int mpll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; + + params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags); + + /* Set the fractional part */ + meson_parm_write(clk->map, &mpll->sdm, sdm); + + /* Set the integer divider part */ + meson_parm_write(clk->map, &mpll->n2, n2); + + return 0; +} + +static int mpll_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + int ret; + + ret = clk_regmap_init(hw); + if (ret) + return ret; + + if (mpll->init_count) + regmap_multi_reg_write(clk->map, mpll->init_regs, + mpll->init_count); + + /* Enable the fractional part */ + meson_parm_write(clk->map, &mpll->sdm_en, 1); + + /* Set spread spectrum if possible */ + if (MESON_PARM_APPLICABLE(&mpll->ssen)) { + unsigned int ss = + mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0; + meson_parm_write(clk->map, &mpll->ssen, ss); + } + + /* Set the magic misc bit if required */ + if (MESON_PARM_APPLICABLE(&mpll->misc)) + meson_parm_write(clk->map, &mpll->misc, 1); + + return 0; +} + +const struct clk_ops meson_clk_mpll_ro_ops = { + .init = clk_regmap_init, + .recalc_rate = mpll_recalc_rate, + .determine_rate = mpll_determine_rate, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ro_ops, "CLK_MESON"); + +const struct clk_ops meson_clk_mpll_ops = { + .recalc_rate = mpll_recalc_rate, + .determine_rate = mpll_determine_rate, + .set_rate = mpll_set_rate, + .init = mpll_init, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic MPLL driver"); +MODULE_AUTHOR("Michael Turquette "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h new file mode 100644 index 000000000..4ffd3aeef --- /dev/null +++ b/drivers/clk/meson/clk-mpll.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_MPLL_H +#define __MESON_CLK_MPLL_H + +#include +#include + +#include "parm.h" + +struct meson_clk_mpll_data { + struct parm sdm; + struct parm sdm_en; + struct parm n2; + struct parm ssen; + struct parm misc; + const struct reg_sequence *init_regs; + unsigned int init_count; + u8 flags; +}; + +#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) +#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1) + +extern const struct clk_ops meson_clk_mpll_ro_ops; +extern const struct clk_ops meson_clk_mpll_ops; + +#endif /* __MESON_CLK_MPLL_H */ diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c new file mode 100644 index 000000000..58dd982e6 --- /dev/null +++ b/drivers/clk/meson/clk-phase.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include + +#include "clk-regmap.h" +#include "clk-phase.h" + +#define phase_step(_width) (360 / (1 << (_width))) + +static inline struct meson_clk_phase_data * +meson_clk_phase_data(struct clk_regmap *clk) +{ + return (struct meson_clk_phase_data *)clk->data; +} + +static int meson_clk_degrees_from_val(unsigned int val, unsigned int width) +{ + return phase_step(width) * val; +} + +static unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) +{ + unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width)); + + /* + * This last calculation is here for cases when degrees is rounded + * to 360, in which case val == (1 << width). + */ + return val % (1 << width); +} + +static int meson_clk_phase_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); + unsigned int val; + + val = meson_parm_read(clk->map, &phase->ph); + + return meson_clk_degrees_from_val(val, phase->ph.width); +} + +static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, phase->ph.width); + meson_parm_write(clk->map, &phase->ph, val); + + return 0; +} + +const struct clk_ops meson_clk_phase_ops = { + .init = clk_regmap_init, + .get_phase = meson_clk_phase_get_phase, + .set_phase = meson_clk_phase_set_phase, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_phase_ops, "CLK_MESON"); + +/* + * This is a special clock for the audio controller. + * The phase of mst_sclk clock output can be controlled independently + * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2). + * Controlling these 3 phases as just one makes things simpler and + * give the same clock view to all the element on the i2s bus. + * If necessary, we can still control the phase in the tdm block + * which makes these independent control redundant. + */ +static inline struct meson_clk_triphase_data * +meson_clk_triphase_data(struct clk_regmap *clk) +{ + return (struct meson_clk_triphase_data *)clk->data; +} + +static int meson_clk_triphase_sync(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + int ret; + + ret = clk_regmap_init(hw); + if (ret) + return ret; + + /* Get phase 0 and sync it to phase 1 and 2 */ + val = meson_parm_read(clk->map, &tph->ph0); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); + + return 0; +} + +static int meson_clk_triphase_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + /* Phase are in sync, reading phase 0 is enough */ + val = meson_parm_read(clk->map, &tph->ph0); + + return meson_clk_degrees_from_val(val, tph->ph0.width); +} + +static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, tph->ph0.width); + meson_parm_write(clk->map, &tph->ph0, val); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); + + return 0; +} + +const struct clk_ops meson_clk_triphase_ops = { + .init = meson_clk_triphase_sync, + .get_phase = meson_clk_triphase_get_phase, + .set_phase = meson_clk_triphase_set_phase, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_triphase_ops, "CLK_MESON"); + +/* + * This is a special clock for the audio controller. + * This drive a bit clock inverter for which the + * opposite value of the inverter bit needs to be manually + * set into another bit + */ +static inline struct meson_sclk_ws_inv_data * +meson_sclk_ws_inv_data(struct clk_regmap *clk) +{ + return (struct meson_sclk_ws_inv_data *)clk->data; +} + +static int meson_sclk_ws_inv_sync(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + int ret; + + ret = clk_regmap_init(hw); + if (ret) + return ret; + + /* Get phase and sync the inverted value to ws */ + val = meson_parm_read(clk->map, &tph->ph); + meson_parm_write(clk->map, &tph->ws, val ? 0 : 1); + + return 0; +} + +static int meson_sclk_ws_inv_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + + val = meson_parm_read(clk->map, &tph->ph); + + return meson_clk_degrees_from_val(val, tph->ph.width); +} + +static int meson_sclk_ws_inv_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, tph->ph.width); + meson_parm_write(clk->map, &tph->ph, val); + meson_parm_write(clk->map, &tph->ws, val ? 0 : 1); + return 0; +} + +const struct clk_ops meson_sclk_ws_inv_ops = { + .init = meson_sclk_ws_inv_sync, + .get_phase = meson_sclk_ws_inv_get_phase, + .set_phase = meson_sclk_ws_inv_set_phase, +}; +EXPORT_SYMBOL_NS_GPL(meson_sclk_ws_inv_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic phase driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-phase.h b/drivers/clk/meson/clk-phase.h new file mode 100644 index 000000000..b637b9b22 --- /dev/null +++ b/drivers/clk/meson/clk-phase.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_PHASE_H +#define __MESON_CLK_PHASE_H + +#include +#include "parm.h" + +struct meson_clk_phase_data { + struct parm ph; +}; + +struct meson_clk_triphase_data { + struct parm ph0; + struct parm ph1; + struct parm ph2; +}; + +struct meson_sclk_ws_inv_data { + struct parm ph; + struct parm ws; +}; + +extern const struct clk_ops meson_clk_phase_ops; +extern const struct clk_ops meson_clk_triphase_ops; +extern const struct clk_ops meson_sclk_ws_inv_ops; + +#endif /* __MESON_CLK_PHASE_H */ diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c new file mode 100644 index 000000000..1ea6579a7 --- /dev/null +++ b/drivers/clk/meson/clk-pll.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * Copyright (c) 2018 Baylibre, SAS. + * Author: Jerome Brunet + */ + +/* + * In the most basic form, a Meson PLL is composed as follows: + * + * PLL + * +--------------------------------+ + * | | + * | +--+ | + * in >>-----[ /N ]--->| | +-----+ | + * | | |------| DCO |---->> out + * | +--------->| | +--v--+ | + * | | +--+ | | + * | | | | + * | +--[ *(M + (F/Fmax) ]<--+ | + * | | + * +--------------------------------+ + * + * out = in * (m + frac / frac_max) / n + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "clk-pll.h" + +static inline struct meson_clk_pll_data * +meson_clk_pll_data(struct clk_regmap *clk) +{ + return (struct meson_clk_pll_data *)clk->data; +} + +static int __pll_round_closest_mult(struct meson_clk_pll_data *pll) +{ + if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) && + !MESON_PARM_APPLICABLE(&pll->frac)) + return 1; + + return 0; +} + +static unsigned long __pll_params_to_rate(unsigned long parent_rate, + unsigned int m, unsigned int n, + unsigned int frac, + struct meson_clk_pll_data *pll) +{ + u64 rate = (u64)parent_rate * m; + unsigned int frac_max = pll->frac_max ? pll->frac_max : + (1 << pll->frac.width); + + if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { + u64 frac_rate = (u64)parent_rate * frac; + + rate += DIV_ROUND_UP_ULL(frac_rate, frac_max); + } + + return DIV_ROUND_UP_ULL(rate, n); +} + +static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + unsigned int m, n, frac; + + n = meson_parm_read(clk->map, &pll->n); + + /* + * On some HW, N is set to zero on init. This value is invalid as + * it would result in a division by zero. The rate can't be + * calculated in this case + */ + if (n == 0) + return 0; + + m = meson_parm_read(clk->map, &pll->m); + + frac = MESON_PARM_APPLICABLE(&pll->frac) ? + meson_parm_read(clk->map, &pll->frac) : + 0; + + return __pll_params_to_rate(parent_rate, m, n, frac, pll); +} + +static unsigned int __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + unsigned int m, + unsigned int n, + struct meson_clk_pll_data *pll) +{ + unsigned int frac_max = pll->frac_max ? pll->frac_max : + (1 << pll->frac.width); + u64 val = (u64)rate * n; + + /* Bail out if we are already over the requested rate */ + if (rate < parent_rate * m / n) + return 0; + + if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) + val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); + else + val = div_u64(val * frac_max, parent_rate); + + val -= m * frac_max; + + return min((unsigned int)val, (frac_max - 1)); +} + +static bool meson_clk_pll_is_better(unsigned long rate, + unsigned long best, + unsigned long now, + struct meson_clk_pll_data *pll) +{ + if (__pll_round_closest_mult(pll)) { + /* Round Closest */ + if (abs(now - rate) < abs(best - rate)) + return true; + } else { + /* Round down */ + if (now <= rate && best < now) + return true; + } + + return false; +} + +static int meson_clk_get_pll_table_index(unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) +{ + if (!pll->table[index].n) + return -EINVAL; + + *m = pll->table[index].m; + *n = pll->table[index].n; + + return 0; +} + +static unsigned int meson_clk_get_pll_range_m(unsigned long rate, + unsigned long parent_rate, + unsigned int n, + struct meson_clk_pll_data *pll) +{ + u64 val = (u64)rate * n; + + if (__pll_round_closest_mult(pll)) + return DIV_ROUND_CLOSEST_ULL(val, parent_rate); + + return div_u64(val, parent_rate); +} + +static int meson_clk_get_pll_range_index(unsigned long rate, + unsigned long parent_rate, + unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) +{ + *n = index + 1; + + /* Check the predivider range */ + if (*n >= (1 << pll->n.width)) + return -EINVAL; + + if (*n == 1) { + /* Get the boundaries out the way */ + if (rate <= pll->range->min * parent_rate) { + *m = pll->range->min; + return -ENODATA; + } else if (rate >= pll->range->max * parent_rate) { + *m = pll->range->max; + return -ENODATA; + } + } + + *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll); + + /* the pre-divider gives a multiplier too big - stop */ + if (*m >= (1 << pll->m.width)) + return -EINVAL; + + return 0; +} + +static int meson_clk_get_pll_get_index(unsigned long rate, + unsigned long parent_rate, + unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) +{ + if (pll->range) + return meson_clk_get_pll_range_index(rate, parent_rate, + index, m, n, pll); + else if (pll->table) + return meson_clk_get_pll_table_index(index, m, n, pll); + + return -EINVAL; +} + +static int meson_clk_get_pll_settings(unsigned long rate, + unsigned long parent_rate, + unsigned int *best_m, + unsigned int *best_n, + struct meson_clk_pll_data *pll) +{ + unsigned long best = 0, now = 0; + unsigned int i, m, n; + int ret; + + for (i = 0, ret = 0; !ret; i++) { + ret = meson_clk_get_pll_get_index(rate, parent_rate, + i, &m, &n, pll); + if (ret == -EINVAL) + break; + + now = __pll_params_to_rate(parent_rate, m, n, 0, pll); + if (meson_clk_pll_is_better(rate, best, now, pll)) { + best = now; + *best_m = m; + *best_n = n; + + if (now == rate) + break; + } + } + + return best ? 0 : -EINVAL; +} + +static int meson_clk_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + unsigned int m, n, frac; + unsigned long round; + int ret; + + ret = meson_clk_get_pll_settings(req->rate, req->best_parent_rate, + &m, &n, pll); + if (ret) + return ret; + + round = __pll_params_to_rate(req->best_parent_rate, m, n, 0, pll); + + if (!MESON_PARM_APPLICABLE(&pll->frac) || req->rate == round) { + req->rate = round; + return 0; + } + + /* + * The rate provided by the setting is not an exact match, let's + * try to improve the result using the fractional parameter + */ + frac = __pll_params_with_frac(req->rate, req->best_parent_rate, m, n, pll); + req->rate = __pll_params_to_rate(req->best_parent_rate, m, n, frac, pll); + + return 0; +} + +static int meson_clk_pll_wait_lock(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + int delay = 5000; + + do { + /* Is the clock locked now ? Time out after 100ms. */ + if (meson_parm_read(clk->map, &pll->l)) + return 0; + + udelay(20); + } while (--delay); + + return -ETIMEDOUT; +} + +static int meson_clk_pll_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + if (MESON_PARM_APPLICABLE(&pll->rst) && + meson_parm_read(clk->map, &pll->rst)) + return 0; + + if (!meson_parm_read(clk->map, &pll->en) || + !meson_parm_read(clk->map, &pll->l)) + return 0; + + return 1; +} + +static int meson_clk_pll_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + int ret; + + ret = clk_regmap_init(hw); + if (ret) + return ret; + + /* + * Keep the clock running, which was already initialized and enabled + * from the bootloader stage, to avoid any glitches. + */ + if ((pll->flags & CLK_MESON_PLL_NOINIT_ENABLED) && + meson_clk_pll_is_enabled(hw)) + return 0; + + if (pll->init_count) { + if (MESON_PARM_APPLICABLE(&pll->rst)) + meson_parm_write(clk->map, &pll->rst, 1); + + regmap_multi_reg_write(clk->map, pll->init_regs, + pll->init_count); + + if (MESON_PARM_APPLICABLE(&pll->rst)) + meson_parm_write(clk->map, &pll->rst, 0); + } + + return 0; +} + +static int meson_clk_pcie_pll_enable(struct clk_hw *hw) +{ + int retries = 10; + + do { + meson_clk_pll_init(hw); + if (!meson_clk_pll_wait_lock(hw)) + return 0; + pr_info("Retry enabling PCIe PLL clock\n"); + } while (--retries); + + return -EIO; +} + +static int meson_clk_pll_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* do nothing if the PLL is already enabled */ + if (clk_hw_is_enabled(hw)) + return 0; + + /* Make sure the pll is in reset */ + if (MESON_PARM_APPLICABLE(&pll->rst)) + meson_parm_write(clk->map, &pll->rst, 1); + + /* Enable the pll */ + meson_parm_write(clk->map, &pll->en, 1); + + /* Take the pll out reset */ + if (MESON_PARM_APPLICABLE(&pll->rst)) + meson_parm_write(clk->map, &pll->rst, 0); + + /* + * Compared with the previous SoCs, self-adaption current module + * is newly added for A1, keep the new power-on sequence to enable the + * PLL. The sequence is: + * 1. enable the pll, delay for 10us + * 2. enable the pll self-adaption current module, delay for 40us + * 3. enable the lock detect module + */ + if (MESON_PARM_APPLICABLE(&pll->current_en)) { + udelay(10); + meson_parm_write(clk->map, &pll->current_en, 1); + udelay(40); + } + + if (MESON_PARM_APPLICABLE(&pll->l_detect)) { + meson_parm_write(clk->map, &pll->l_detect, 1); + meson_parm_write(clk->map, &pll->l_detect, 0); + } + + if (meson_clk_pll_wait_lock(hw)) + return -EIO; + + return 0; +} + +static void meson_clk_pll_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Put the pll is in reset */ + if (MESON_PARM_APPLICABLE(&pll->rst)) + meson_parm_write(clk->map, &pll->rst, 1); + + /* Disable the pll */ + meson_parm_write(clk->map, &pll->en, 0); + + /* Disable PLL internal self-adaption current module */ + if (MESON_PARM_APPLICABLE(&pll->current_en)) + meson_parm_write(clk->map, &pll->current_en, 0); +} + +static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + unsigned int enabled, m, n, frac = 0; + unsigned long old_rate; + int ret; + + if (parent_rate == 0 || rate == 0) + return -EINVAL; + + old_rate = clk_hw_get_rate(hw); + + ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll); + if (ret) + return ret; + + enabled = meson_parm_read(clk->map, &pll->en); + if (enabled) + meson_clk_pll_disable(hw); + + meson_parm_write(clk->map, &pll->n, n); + meson_parm_write(clk->map, &pll->m, m); + + if (MESON_PARM_APPLICABLE(&pll->frac)) { + frac = __pll_params_with_frac(rate, parent_rate, m, n, pll); + meson_parm_write(clk->map, &pll->frac, frac); + } + + /* If the pll is stopped, bail out now */ + if (!enabled) + return 0; + + ret = meson_clk_pll_enable(hw); + if (ret) { + pr_warn("%s: pll %s didn't lock, trying to set old rate %lu\n", + __func__, clk_hw_get_name(hw), old_rate); + /* + * FIXME: Do we really need/want this HACK ? + * It looks unsafe. what happens if the clock gets into a + * broken state and we can't lock back on the old_rate ? Looks + * like an infinite recursion is possible + */ + meson_clk_pll_set_rate(hw, old_rate, parent_rate); + } + + return ret; +} + +/* + * The Meson G12A PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + * To simplify, re-use the _init() op to enable the PLL and keep + * the other ops except set_rate since the rate is fixed. + */ +const struct clk_ops meson_clk_pcie_pll_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_clk_pll_recalc_rate, + .determine_rate = meson_clk_pll_determine_rate, + .is_enabled = meson_clk_pll_is_enabled, + .enable = meson_clk_pcie_pll_enable, + .disable = meson_clk_pll_disable +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_pcie_pll_ops, "CLK_MESON"); + +const struct clk_ops meson_clk_pll_ops = { + .init = meson_clk_pll_init, + .recalc_rate = meson_clk_pll_recalc_rate, + .determine_rate = meson_clk_pll_determine_rate, + .set_rate = meson_clk_pll_set_rate, + .is_enabled = meson_clk_pll_is_enabled, + .enable = meson_clk_pll_enable, + .disable = meson_clk_pll_disable +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ops, "CLK_MESON"); + +const struct clk_ops meson_clk_pll_ro_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_clk_pll_recalc_rate, + .is_enabled = meson_clk_pll_is_enabled, +}; +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ro_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic PLL driver"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h new file mode 100644 index 000000000..949157fb7 --- /dev/null +++ b/drivers/clk/meson/clk-pll.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_PLL_H +#define __MESON_CLK_PLL_H + +#include +#include +#include "parm.h" + +struct pll_params_table { + unsigned int m; + unsigned int n; +}; + +struct pll_mult_range { + unsigned int min; + unsigned int max; +}; + +#define PLL_PARAMS(_m, _n) \ + { \ + .m = (_m), \ + .n = (_n), \ + } + +#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) +#define CLK_MESON_PLL_NOINIT_ENABLED BIT(1) + +struct meson_clk_pll_data { + struct parm en; + struct parm m; + struct parm n; + struct parm frac; + struct parm l; + struct parm rst; + struct parm current_en; + struct parm l_detect; + const struct reg_sequence *init_regs; + unsigned int init_count; + const struct pll_params_table *table; + const struct pll_mult_range *range; + unsigned int frac_max; + u8 flags; +}; + +extern const struct clk_ops meson_clk_pll_ro_ops; +extern const struct clk_ops meson_clk_pll_ops; +extern const struct clk_ops meson_clk_pcie_pll_ops; + +#endif /* __MESON_CLK_PLL_H */ diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c new file mode 100644 index 000000000..1ed56fe63 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include "clk-regmap.h" + +int clk_regmap_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct device_node *np, *parent_np; + struct device *dev; + + /* Allow regmap to be preset as it was historically done */ + if (clk->map) + return 0; + + /* + * FIXME: what follows couples the controller implementation + * and clk_regmap clock type. This situation is not desirable + * but temporary, until the controller is able to register + * a hook to initialize a clock type + */ + + /* Check the usual dev enabled controller with an basic IO regmap */ + dev = clk_hw_get_dev(hw); + if (dev) { + clk->map = dev_get_regmap(dev, NULL); + if (clk->map) + return 0; + } + + /* Move on to early and syscon based controllers */ + np = clk_hw_get_of_node(hw); + if (np) { + parent_np = of_get_parent(np); + clk->map = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); + + if (!IS_ERR_OR_NULL(clk->map)) + return 0; + } + + /* Bail out if regmap can't be found */ + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(clk_regmap_init, "CLK_MESON"); + +static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + + set ^= enable; + + return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx), + set ? BIT(gate->bit_idx) : 0); +} + +static int clk_regmap_gate_enable(struct clk_hw *hw) +{ + return clk_regmap_gate_endisable(hw, 1); +} + +static void clk_regmap_gate_disable(struct clk_hw *hw) +{ + clk_regmap_gate_endisable(hw, 0); +} + +static int clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + unsigned int val; + + regmap_read(clk->map, gate->offset, &val); + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + val ^= BIT(gate->bit_idx); + + val &= BIT(gate->bit_idx); + + return val ? 1 : 0; +} + +const struct clk_ops clk_regmap_gate_ops = { + .init = clk_regmap_init, + .enable = clk_regmap_gate_enable, + .disable = clk_regmap_gate_disable, + .is_enabled = clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, "CLK_MESON"); + +const struct clk_ops clk_regmap_gate_ro_ops = { + .init = clk_regmap_init, + .is_enabled = clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, "CLK_MESON"); + +static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>= div->shift; + val &= clk_div_mask(div->width); + return divider_recalc_rate(hw, prate, val, div->table, div->flags, + div->width); +} + +static int clk_regmap_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + /* if read only, just return current value */ + if (div->flags & CLK_DIVIDER_READ_ONLY) { + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + return ret; + + val >>= div->shift; + val &= clk_div_mask(div->width); + + return divider_ro_determine_rate(hw, req, div->table, + div->width, div->flags, val); + } + + return divider_determine_rate(hw, req, div->table, div->width, + div->flags); +} + +static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, div->table, div->width, + div->flags); + if (ret < 0) + return ret; + + val = (unsigned int)ret << div->shift; + return regmap_update_bits(clk->map, div->offset, + clk_div_mask(div->width) << div->shift, val); +}; + +/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ + +const struct clk_ops clk_regmap_divider_ops = { + .init = clk_regmap_init, + .recalc_rate = clk_regmap_div_recalc_rate, + .determine_rate = clk_regmap_div_determine_rate, + .set_rate = clk_regmap_div_set_rate, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, "CLK_MESON"); + +const struct clk_ops clk_regmap_divider_ro_ops = { + .init = clk_regmap_init, + .recalc_rate = clk_regmap_div_recalc_rate, + .determine_rate = clk_regmap_div_determine_rate, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, "CLK_MESON"); + +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, mux->offset, &val); + if (ret) + return ret; + + val >>= mux->shift; + val &= mux->mask; + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index); + + return regmap_update_bits(clk->map, mux->offset, + mux->mask << mux->shift, + val << mux->shift); +} + +static int clk_regmap_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + + return clk_mux_determine_rate_flags(hw, req, mux->flags); +} + +const struct clk_ops clk_regmap_mux_ops = { + .init = clk_regmap_init, + .get_parent = clk_regmap_mux_get_parent, + .set_parent = clk_regmap_mux_set_parent, + .determine_rate = clk_regmap_mux_determine_rate, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, "CLK_MESON"); + +const struct clk_ops clk_regmap_mux_ro_ops = { + .init = clk_regmap_init, + .get_parent = clk_regmap_mux_get_parent, +}; +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h new file mode 100644 index 000000000..8e5c39b02 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __CLK_REGMAP_H +#define __CLK_REGMAP_H + +#include +#include +#include + +/** + * struct clk_regmap - regmap backed clock + * + * @hw: handle between common and hardware-specific interfaces + * @map: pointer to the regmap structure controlling the clock + * @data: data specific to the clock type + * + * Clock which is controlled by regmap backed registers. The actual type of + * of the clock is controlled by the clock_ops and data. + */ +struct clk_regmap { + struct clk_hw hw; + struct regmap *map; + void *data; +}; + +static inline struct clk_regmap *to_clk_regmap(struct clk_hw *hw) +{ + return container_of(hw, struct clk_regmap, hw); +} + +/* clk_regmap init op to get and cache regmap from the controllers */ +int clk_regmap_init(struct clk_hw *hw); + +/** + * struct clk_regmap_gate_data - regmap backed gate specific data + * + * @offset: offset of the register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored + */ +struct clk_regmap_gate_data { + unsigned int offset; + u8 bit_idx; + u8 flags; +}; + +static inline struct clk_regmap_gate_data * +clk_get_regmap_gate_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_gate_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_gate_ops; +extern const struct clk_ops clk_regmap_gate_ro_ops; + +/** + * struct clk_regmap_div_data - regmap backed adjustable divider specific data + * + * @offset: offset of the register controlling the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @table: array of value/divider pairs, last entry should have div = 0 + * + * Flags: + * Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored + */ +struct clk_regmap_div_data { + unsigned int offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; +}; + +static inline struct clk_regmap_div_data * +clk_get_regmap_div_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_div_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_divider_ops; +extern const struct clk_ops clk_regmap_divider_ro_ops; + +/** + * struct clk_regmap_mux_data - regmap backed multiplexer clock specific data + * + * @hw: handle between common and hardware-specific interfaces + * @offset: offset of theregister controlling multiplexer + * @table: array of parent indexed register values + * @shift: shift to multiplexer bit field + * @mask: mask of mutliplexer bit field + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_divider except CLK_MUX_HIWORD_MASK which is ignored + */ +struct clk_regmap_mux_data { + unsigned int offset; + u32 *table; + u32 mask; + u8 shift; + u8 flags; +}; + +static inline struct clk_regmap_mux_data * +clk_get_regmap_mux_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_mux_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_mux_ops; +extern const struct clk_ops clk_regmap_mux_ro_ops; + +#endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c new file mode 100644 index 000000000..96981da27 --- /dev/null +++ b/drivers/clk/meson/g12a-aoclk.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2019 Baylibre SAS. + * Author: Neil Armstrong + */ +#include +#include +#include +#include +#include +#include "meson-aoclk.h" + +#include "clk-regmap.h" +#include "clk-dualdiv.h" + +#include +#include + +/* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. + */ +#define AO_RTI_STATUS_REG3 0x0C +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_CLK_GATE0 0x4c +#define AO_CLK_GATE0_SP 0x50 +#define AO_OSCIN_CNTL 0x58 +#define AO_CEC_CLK_CNTL_REG0 0x74 +#define AO_CEC_CLK_CNTL_REG1 0x78 +#define AO_SAR_CLK 0x90 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + +static const struct clk_parent_data g12a_ao_pclk_parents = { .fw_name = "mpeg-clk" }; + +#define G12A_AO_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(g12a_ao_##_name, _reg, _bit, &g12a_ao_pclk_parents, _flags) + +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static G12A_AO_PCLK(ahb, AO_CLK_GATE0, 0, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ir_in, AO_CLK_GATE0, 1, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(i2c_m0, AO_CLK_GATE0, 2, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(i2c_s0, AO_CLK_GATE0, 3, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(uart, AO_CLK_GATE0, 4, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(prod_i2c, AO_CLK_GATE0, 5, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(uart2, AO_CLK_GATE0, 6, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ir_out, AO_CLK_GATE0, 7, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(saradc, AO_CLK_GATE0, 8, CLK_IGNORE_UNUSED); + +static G12A_AO_PCLK(mailbox, AO_CLK_GATE0_SP, 0, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m3, AO_CLK_GATE0_SP, 1, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(ahb_sram, AO_CLK_GATE0_SP, 2, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(rti, AO_CLK_GATE0_SP, 3, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m4_fclk, AO_CLK_GATE0_SP, 4, CLK_IGNORE_UNUSED); +static G12A_AO_PCLK(m4_hclk, AO_CLK_GATE0_SP, 5, CLK_IGNORE_UNUSED); + +static struct clk_regmap g12a_ao_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +/* 32k_by_oscin clock */ + +static struct clk_regmap g12a_ao_32k_by_oscin_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_by_oscin_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_cts_oscin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_ao_32k_by_oscin_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = g12a_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_by_oscin_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_32k_by_oscin_pre.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_ao_32k_by_oscin_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_by_oscin_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_32k_by_oscin_div.hw, + &g12a_ao_32k_by_oscin_pre.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_32k_by_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_by_oscin", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_32k_by_oscin_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* cec clock */ + +static struct clk_regmap g12a_ao_cec_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CLK_CNTL_REG0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_cts_oscin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_ao_cec_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_CEC_CLK_CNTL_REG1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_CEC_CLK_CNTL_REG1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 28, + .width = 1, + }, + .table = g12a_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_cec_pre.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_ao_cec_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CEC_CLK_CNTL_REG1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_cec_div.hw, + &g12a_ao_cec_pre.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_cec = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CLK_CNTL_REG0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cec", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_cec_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &g12a_ao_32k_by_oscin.hw }, + { .fw_name = "ext-32k-0", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 8, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + /* + * NOTE: this is one of the infamous clock the pwm driver + * can request directly by its global name. It's wrong but + * there is not much we can do about it until the support + * for the old pwm bindings is dropped + */ + .name = "g12a_ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &g12a_ao_cts_rtc_oscin.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_saradc_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_SAR_CLK, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_ao_clk81.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap g12a_ao_saradc_div = { + .data = &(struct clk_regmap_div_data) { + .offset = AO_SAR_CLK, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_saradc_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ao_saradc_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = AO_SAR_CLK, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_saradc_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ao_saradc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const unsigned int g12a_ao_reset[] = { + [RESET_AO_IR_IN] = 16, + [RESET_AO_UART] = 17, + [RESET_AO_I2C_M] = 18, + [RESET_AO_I2C_S] = 19, + [RESET_AO_SAR_ADC] = 20, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_OUT] = 23, +}; + +static struct clk_hw *g12a_ao_hw_clks[] = { + [CLKID_AO_AHB] = &g12a_ao_ahb.hw, + [CLKID_AO_IR_IN] = &g12a_ao_ir_in.hw, + [CLKID_AO_I2C_M0] = &g12a_ao_i2c_m0.hw, + [CLKID_AO_I2C_S0] = &g12a_ao_i2c_s0.hw, + [CLKID_AO_UART] = &g12a_ao_uart.hw, + [CLKID_AO_PROD_I2C] = &g12a_ao_prod_i2c.hw, + [CLKID_AO_UART2] = &g12a_ao_uart2.hw, + [CLKID_AO_IR_OUT] = &g12a_ao_ir_out.hw, + [CLKID_AO_SAR_ADC] = &g12a_ao_saradc.hw, + [CLKID_AO_MAILBOX] = &g12a_ao_mailbox.hw, + [CLKID_AO_M3] = &g12a_ao_m3.hw, + [CLKID_AO_AHB_SRAM] = &g12a_ao_ahb_sram.hw, + [CLKID_AO_RTI] = &g12a_ao_rti.hw, + [CLKID_AO_M4_FCLK] = &g12a_ao_m4_fclk.hw, + [CLKID_AO_M4_HCLK] = &g12a_ao_m4_hclk.hw, + [CLKID_AO_CLK81] = &g12a_ao_clk81.hw, + [CLKID_AO_SAR_ADC_SEL] = &g12a_ao_saradc_mux.hw, + [CLKID_AO_SAR_ADC_DIV] = &g12a_ao_saradc_div.hw, + [CLKID_AO_SAR_ADC_CLK] = &g12a_ao_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &g12a_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &g12a_ao_32k_by_oscin_pre.hw, + [CLKID_AO_32K_DIV] = &g12a_ao_32k_by_oscin_div.hw, + [CLKID_AO_32K_SEL] = &g12a_ao_32k_by_oscin_sel.hw, + [CLKID_AO_32K] = &g12a_ao_32k_by_oscin.hw, + [CLKID_AO_CEC_PRE] = &g12a_ao_cec_pre.hw, + [CLKID_AO_CEC_DIV] = &g12a_ao_cec_div.hw, + [CLKID_AO_CEC_SEL] = &g12a_ao_cec_sel.hw, + [CLKID_AO_CEC] = &g12a_ao_cec.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &g12a_ao_cts_rtc_oscin.hw, +}; + +static const struct meson_aoclk_data g12a_ao_clkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(g12a_ao_reset), + .reset = g12a_ao_reset, + .clkc_data = { + .hw_clks = { + .hws = g12a_ao_hw_clks, + .num = ARRAY_SIZE(g12a_ao_hw_clks), + }, + }, +}; + +static const struct of_device_id g12a_ao_clkc_match_table[] = { + { + .compatible = "amlogic,meson-g12a-aoclkc", + .data = &g12a_ao_clkc_data.clkc_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, g12a_ao_clkc_match_table); + +static struct platform_driver g12a_ao_clkc_driver = { + .probe = meson_aoclkc_probe, + .driver = { + .name = "g12a-aoclkc", + .of_match_table = g12a_ao_clkc_match_table, + }, +}; +module_platform_driver(g12a_ao_clkc_driver); + +MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c new file mode 100644 index 000000000..d0d4c7b6d --- /dev/null +++ b/drivers/clk/meson/g12a.c @@ -0,0 +1,5473 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-G12A Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + * Author: Jian Hu + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "clk-cpu-dyndiv.h" +#include "vid-pll-div.h" +#include "vclk.h" +#include "meson-clkc-utils.h" + +#include + +#define HHI_MIPI_CNTL0 0x000 +#define HHI_MIPI_CNTL1 0x004 +#define HHI_MIPI_CNTL2 0x008 +#define HHI_MIPI_STS 0x00c +#define HHI_GP0_PLL_CNTL0 0x040 +#define HHI_GP0_PLL_CNTL1 0x044 +#define HHI_GP0_PLL_CNTL2 0x048 +#define HHI_GP0_PLL_CNTL3 0x04c +#define HHI_GP0_PLL_CNTL4 0x050 +#define HHI_GP0_PLL_CNTL5 0x054 +#define HHI_GP0_PLL_CNTL6 0x058 +#define HHI_GP0_PLL_STS 0x05c +#define HHI_GP1_PLL_CNTL0 0x060 +#define HHI_GP1_PLL_CNTL1 0x064 +#define HHI_GP1_PLL_CNTL2 0x068 +#define HHI_GP1_PLL_CNTL3 0x06c +#define HHI_GP1_PLL_CNTL4 0x070 +#define HHI_GP1_PLL_CNTL5 0x074 +#define HHI_GP1_PLL_CNTL6 0x078 +#define HHI_GP1_PLL_STS 0x07c +#define HHI_PCIE_PLL_CNTL0 0x098 +#define HHI_PCIE_PLL_CNTL1 0x09c +#define HHI_PCIE_PLL_CNTL2 0x0a0 +#define HHI_PCIE_PLL_CNTL3 0x0a4 +#define HHI_PCIE_PLL_CNTL4 0x0a8 +#define HHI_PCIE_PLL_CNTL5 0x0ac +#define HHI_PCIE_PLL_STS 0x0b8 +#define HHI_HIFI_PLL_CNTL0 0x0d8 +#define HHI_HIFI_PLL_CNTL1 0x0dc +#define HHI_HIFI_PLL_CNTL2 0x0e0 +#define HHI_HIFI_PLL_CNTL3 0x0e4 +#define HHI_HIFI_PLL_CNTL4 0x0e8 +#define HHI_HIFI_PLL_CNTL5 0x0ec +#define HHI_HIFI_PLL_CNTL6 0x0f0 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12c +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_OTHER2 0x154 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c +#define HHI_VID_CLK_DIV 0x164 +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_AUD_CLK_CNTL 0x178 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_TS_CLK_CNTL 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_VID_PLL_CLK_DIV 0x1a0 +#define HHI_MALI_CLK_CNTL 0x1b0 +#define HHI_VPU_CLKC_CNTL 0x1b4 +#define HHI_VPU_CLK_CNTL 0x1bc +#define HHI_ISP_CLK_CNTL 0x1c0 +#define HHI_NNA_CLK_CNTL 0x1c8 +#define HHI_HDMI_CLK_CNTL 0x1cc +#define HHI_VDEC_CLK_CNTL 0x1e0 +#define HHI_VDEC2_CLK_CNTL 0x1e4 +#define HHI_VDEC3_CLK_CNTL 0x1e8 +#define HHI_VDEC4_CLK_CNTL 0x1ec +#define HHI_HDCP22_CLK_CNTL 0x1f0 +#define HHI_VAPBCLK_CNTL 0x1f4 +#define HHI_SYS_CPUB_CLK_CNTL1 0x200 +#define HHI_SYS_CPUB_CLK_CNTL 0x208 +#define HHI_VPU_CLKB_CNTL 0x20c +#define HHI_SYS_CPU_CLK_CNTL2 0x210 +#define HHI_SYS_CPU_CLK_CNTL3 0x214 +#define HHI_SYS_CPU_CLK_CNTL4 0x218 +#define HHI_SYS_CPU_CLK_CNTL5 0x21c +#define HHI_SYS_CPU_CLK_CNTL6 0x220 +#define HHI_GEN_CLK_CNTL 0x228 +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 +#define HHI_MIPIDSI_PHY_CLK_CNTL 0x254 +#define HHI_NAND_CLK_CNTL 0x25c +#define HHI_SD_EMMC_CLK_CNTL 0x264 +#define HHI_MPLL_CNTL0 0x278 +#define HHI_MPLL_CNTL1 0x27c +#define HHI_MPLL_CNTL2 0x280 +#define HHI_MPLL_CNTL3 0x284 +#define HHI_MPLL_CNTL4 0x288 +#define HHI_MPLL_CNTL5 0x28c +#define HHI_MPLL_CNTL6 0x290 +#define HHI_MPLL_CNTL7 0x294 +#define HHI_MPLL_CNTL8 0x298 +#define HHI_FIX_PLL_CNTL0 0x2a0 +#define HHI_FIX_PLL_CNTL1 0x2a4 +#define HHI_FIX_PLL_CNTL3 0x2ac +#define HHI_SYS_PLL_CNTL0 0x2f4 +#define HHI_SYS_PLL_CNTL1 0x2f8 +#define HHI_SYS_PLL_CNTL2 0x2fc +#define HHI_SYS_PLL_CNTL3 0x300 +#define HHI_SYS_PLL_CNTL4 0x304 +#define HHI_SYS_PLL_CNTL5 0x308 +#define HHI_SYS_PLL_CNTL6 0x30c +#define HHI_HDMI_PLL_CNTL0 0x320 +#define HHI_HDMI_PLL_CNTL1 0x324 +#define HHI_HDMI_PLL_CNTL2 0x328 +#define HHI_HDMI_PLL_CNTL3 0x32c +#define HHI_HDMI_PLL_CNTL4 0x330 +#define HHI_HDMI_PLL_CNTL5 0x334 +#define HHI_HDMI_PLL_CNTL6 0x338 +#define HHI_SPICC_CLK_CNTL 0x3dc +#define HHI_SYS1_PLL_CNTL0 0x380 +#define HHI_SYS1_PLL_CNTL1 0x384 +#define HHI_SYS1_PLL_CNTL2 0x388 +#define HHI_SYS1_PLL_CNTL3 0x38c +#define HHI_SYS1_PLL_CNTL4 0x390 +#define HHI_SYS1_PLL_CNTL5 0x394 +#define HHI_SYS1_PLL_CNTL6 0x398 + +static struct clk_regmap g12a_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_FIX_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_FIX_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static const struct pll_mult_range g12a_sys_pll_mult_range = { + .min = 128, + .max = 250, +}; + +static struct clk_regmap g12a_sys_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_sys_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* This clock feeds the CPU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap g12a_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sys_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12b_sys1_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS1_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS1_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_SYS1_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS1_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS1_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_sys_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* This clock feeds the CPU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap g12b_sys1_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS1_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sys_pll_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "sys_pll_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_sys_pll.hw }, + .num_parents = 1, + /* + * This clock is used to debug the sys_pll range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12b_sys1_pll_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "sys1_pll_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll.hw + }, + .num_parents = 1, + /* + * This clock is used to debug the sys_pll range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_fixed_factor g12a_sys_pll_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_div16", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sys_pll_div16_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_sys1_pll_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "sys1_pll_div16", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_sys1_pll_div16_en.hw + }, + .num_parents = 1, + }, +}; + +static const struct pll_mult_range g12a_gp0_pll_mult_range = { + .min = 125, + .max = 255, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence g12a_gp0_pll_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x48681c00 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x33771290 }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_gp1_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP1_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP1_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* This clock feeds the DSU, avoid disabling it */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap sm1_gp1_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP1_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_gp1_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence g12a_hifi_pll_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x6a285c00 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0x65771290 }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_HIFI_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_hifi_pll_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The Meson G12A PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + */ +static const struct reg_sequence g12a_pcie_pll_init_regs[] = { + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, + { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, + { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, + { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, +}; + +/* Keep a single entry table for recalc/round_rate() ops */ +static const struct pll_params_table g12a_pcie_pll_table[] = { + PLL_PARAMS(150, 1), + {0, 0}, +}; + +static struct clk_regmap g12a_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_PCIE_PLL_CNTL1, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_PCIE_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .table = g12a_pcie_pll_table, + .init_regs = g12a_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL0, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ROUND_CLOSEST | + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_dco_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_pcie_pll = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_pll", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_pcie_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL1, + .shift = 0, + .width = 16, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 30, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +/* + * G12/SM1 hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. + * A divider value of 3 should map to /8 but instead map /4 so ignore it. + */ +static const struct clk_div_table g12a_hdmi_pll_od_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { /* sentinel */ } +}; + +static struct clk_regmap g12a_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 16, + .width = 2, + .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 18, + .width = 2, + .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 20, + .width = 2, + .table = g12a_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_pll_od2.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div2_div.hw + }, + .num_parents = 1, + /* + * Similar to fclk_div3, it seems that this clock is used by + * the resident firmware and is required by the platform to + * operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div3_div.hw + }, + .num_parents = 1, + /* + * This clock is used by the resident firmware and is required + * by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + + +static struct clk_fixed_factor g12a_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2p5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fclk_div2p5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_mpll_50m_div = { + .mult = 1, + .div = 80, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll_50m = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_FIX_PLL_CNTL3, + .mask = 0x1, + .shift = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_mpll_50m_div.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_fixed_factor g12a_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "premux0" */ +static struct clk_regmap g12a_cpu_clk_dyn0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "mux0_divn_tcnt" */ +static struct clk_regmap g12a_cpu_clk_dyn0_div = { + .data = &(struct meson_clk_cpu_dyndiv_data){ + .div = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 4, + .width = 6, + }, + .dyn = { + .reg_off = HHI_SYS_CPU_CLK_CNTL0, + .shift = 26, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0_div", + .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap g12a_cpu_clk_dyn0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 2, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn0", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn0_sel.hw, + &g12a_cpu_clk_dyn0_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "premux1" */ +static struct clk_regmap g12a_cpu_clk_dyn1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT + }, +}; + +/* Datasheet names this field as "Mux1_divn_tcnt" */ +static struct clk_regmap g12a_cpu_clk_dyn1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .shift = 20, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn1_sel.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux1" */ +static struct clk_regmap g12a_cpu_clk_dyn1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn1", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn1_sel.hw, + &g12a_cpu_clk_dyn1_div.hw, + }, + .num_parents = 2, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* Datasheet names this field as "Final_dyn_mux_sel" */ +static struct clk_regmap g12a_cpu_clk_dyn = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_dyn", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn0.hw, + &g12a_cpu_clk_dyn1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "Final_mux_sel" */ +static struct clk_regmap g12a_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 11, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12a_sys_pll.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "Final_mux_sel" */ +static struct clk_regmap g12b_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 11, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_dyn.hw, + &g12b_sys1_pll.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "premux0" */ +static struct clk_regmap g12b_cpub_clk_dyn0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x3, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "mux0_divn_tcnt" */ +static struct clk_regmap g12b_cpub_clk_dyn0_div = { + .data = &(struct meson_clk_cpu_dyndiv_data){ + .div = { + .reg_off = HHI_SYS_CPUB_CLK_CNTL, + .shift = 4, + .width = 6, + }, + .dyn = { + .reg_off = HHI_SYS_CPUB_CLK_CNTL, + .shift = 26, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0_div", + .ops = &meson_clk_cpu_dyndiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap g12b_cpub_clk_dyn0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x1, + .shift = 2, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn0", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn0_sel.hw, + &g12b_cpub_clk_dyn0_div.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "premux1" */ +static struct clk_regmap g12b_cpub_clk_dyn1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + }, + .num_parents = 3, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* Datasheet names this field as "Mux1_divn_tcnt" */ +static struct clk_regmap g12b_cpub_clk_dyn1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .shift = 20, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn1_sel.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux1" */ +static struct clk_regmap g12b_cpub_clk_dyn1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn1", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn1_sel.hw, + &g12b_cpub_clk_dyn1_div.hw + }, + .num_parents = 2, + /* This sub-tree is used a parking clock */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* Datasheet names this field as "Final_dyn_mux_sel" */ +static struct clk_regmap g12b_cpub_clk_dyn = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_dyn", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn0.hw, + &g12b_cpub_clk_dyn1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "Final_mux_sel" */ +static struct clk_regmap g12b_cpub_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL, + .mask = 0x1, + .shift = 11, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_dyn.hw, + &g12a_sys_pll.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Datasheet names this field as "premux0" */ +static struct clk_regmap sm1_dsu_clk_dyn0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x3, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn0_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &sm1_gp1_pll.hw }, + }, + .num_parents = 4, + }, +}; + +/* Datasheet names this field as "Mux0_divn_tcnt" */ +static struct clk_regmap sm1_dsu_clk_dyn0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .shift = 4, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn0_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn0_sel.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux0" */ +static struct clk_regmap sm1_dsu_clk_dyn0 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x1, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn0", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn0_sel.hw, + &sm1_dsu_clk_dyn0_div.hw, + }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "premux1" */ +static struct clk_regmap sm1_dsu_clk_dyn1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn1_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &sm1_gp1_pll.hw }, + }, + .num_parents = 4, + }, +}; + +/* Datasheet names this field as "Mux1_divn_tcnt" */ +static struct clk_regmap sm1_dsu_clk_dyn1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .shift = 20, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn1_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn1_sel.hw + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "postmux1" */ +static struct clk_regmap sm1_dsu_clk_dyn1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn1", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn1_sel.hw, + &sm1_dsu_clk_dyn1_div.hw, + }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "Final_dyn_mux_sel" */ +static struct clk_regmap sm1_dsu_clk_dyn = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x1, + .shift = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_dyn", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn0.hw, + &sm1_dsu_clk_dyn1.hw, + }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "Final_mux_sel" */ +static struct clk_regmap sm1_dsu_final_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL5, + .mask = 0x1, + .shift = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk_final", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_dsu_clk_dyn.hw, + &g12a_sys_pll.hw, + }, + .num_parents = 2, + }, +}; + +/* Datasheet names this field as "Cpu_clk_sync_mux_sel" bit 0 */ +static struct clk_regmap sm1_cpu1_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL6, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu1_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk.hw, + /* This CPU also have a dedicated clock tree */ + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "Cpu_clk_sync_mux_sel" bit 1 */ +static struct clk_regmap sm1_cpu2_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL6, + .mask = 0x1, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu2_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk.hw, + /* This CPU also have a dedicated clock tree */ + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "Cpu_clk_sync_mux_sel" bit 2 */ +static struct clk_regmap sm1_cpu3_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL6, + .mask = 0x1, + .shift = 26, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu3_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk.hw, + /* This CPU also have a dedicated clock tree */ + }, + .num_parents = 1, + }, +}; + +/* Datasheet names this field as "Cpu_clk_sync_mux_sel" bit 4 */ +static struct clk_regmap sm1_dsu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL6, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "dsu_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk.hw, + &sm1_dsu_final_clk.hw, + }, + .num_parents = 2, + }, +}; + +static int g12a_cpu_clk_mux_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + if (event == POST_RATE_CHANGE || event == PRE_RATE_CHANGE) { + /* Wait for clock propagation before/after changing the mux */ + udelay(100); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static struct notifier_block g12a_cpu_clk_mux_nb = { + .notifier_call = g12a_cpu_clk_mux_notifier_cb, +}; + +struct g12a_cpu_clk_dyn_nb_data { + struct notifier_block nb; + struct clk_hw *xtal; + struct clk_hw *cpu_clk_dyn; + struct clk_hw *cpu_clk_postmux0; + struct clk_hw *cpu_clk_postmux1; + struct clk_hw *cpu_clk_premux1; +}; + +static int g12a_cpu_clk_dyn_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct g12a_cpu_clk_dyn_nb_data *nb_data = + container_of(nb, struct g12a_cpu_clk_dyn_nb_data, nb); + + switch (event) { + case PRE_RATE_CHANGE: + /* + * This notifier means cpu_clk_dyn0 clock will be changed + * to feed cpu_clk, this is the current path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_dyn0 + * \- cpu_clk_dyn0_div + * \- cpu_clk_dyn0_sel + * \- fclk_div3 or fclk_div2 + * OR + * \- cpu_clk_dyn0_sel + * \- fclk_div3 or fclk_div2 + */ + + /* Setup cpu_clk_dyn1_sel to xtal */ + clk_hw_set_parent(nb_data->cpu_clk_premux1, + nb_data->xtal); + + /* Setup cpu_clk_dyn1 to bypass divider */ + clk_hw_set_parent(nb_data->cpu_clk_postmux1, + nb_data->cpu_clk_premux1); + + /* Switch to parking clk on cpu_clk_postmux1 */ + clk_hw_set_parent(nb_data->cpu_clk_dyn, + nb_data->cpu_clk_postmux1); + + /* + * Now, cpu_clk is 24MHz in the current path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_dyn1 + * \- cpu_clk_dyn1_sel + * \- xtal + */ + + udelay(100); + + return NOTIFY_OK; + + case POST_RATE_CHANGE: + /* + * The cpu_clk_dyn0 has ben updated, now switch back + * cpu_clk_dyn to cpu_clk_dyn0 and take the changes + * in account. + */ + + /* Configure cpu_clk_dyn back to cpu_clk_postmux0 */ + clk_hw_set_parent(nb_data->cpu_clk_dyn, + nb_data->cpu_clk_postmux0); + + /* + * new path : + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_dyn0 + * \- cpu_clk_dyn0_div + * \- cpu_clk_dyn0_sel + * \- fclk_div3 or fclk_div2 + * OR + * \- cpu_clk_dyn0_sel + * \- fclk_div3 or fclk_div2 + */ + + udelay(100); + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} + +static struct g12a_cpu_clk_dyn_nb_data g12a_cpu_clk_dyn0_nb_data = { + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .cpu_clk_postmux0 = &g12a_cpu_clk_dyn0.hw, + .cpu_clk_postmux1 = &g12a_cpu_clk_dyn1.hw, + .cpu_clk_premux1 = &g12a_cpu_clk_dyn1_sel.hw, + .nb.notifier_call = g12a_cpu_clk_dyn_notifier_cb, +}; + +static struct g12a_cpu_clk_dyn_nb_data g12b_cpub_clk_dyn0_nb_data = { + .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, + .cpu_clk_postmux0 = &g12b_cpub_clk_dyn0.hw, + .cpu_clk_postmux1 = &g12b_cpub_clk_dyn1.hw, + .cpu_clk_premux1 = &g12b_cpub_clk_dyn1_sel.hw, + .nb.notifier_call = g12a_cpu_clk_dyn_notifier_cb, +}; + +struct g12a_sys_pll_nb_data { + struct notifier_block nb; + struct clk_hw *sys_pll; + struct clk_hw *cpu_clk; + struct clk_hw *cpu_clk_dyn; +}; + +static int g12a_sys_pll_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct g12a_sys_pll_nb_data *nb_data = + container_of(nb, struct g12a_sys_pll_nb_data, nb); + + switch (event) { + case PRE_RATE_CHANGE: + /* + * This notifier means sys_pll clock will be changed + * to feed cpu_clk, this the current path : + * cpu_clk + * \- sys_pll + * \- sys_pll_dco + */ + + /* Configure cpu_clk to use cpu_clk_dyn */ + clk_hw_set_parent(nb_data->cpu_clk, + nb_data->cpu_clk_dyn); + + /* + * Now, cpu_clk uses the dyn path + * cpu_clk + * \- cpu_clk_dyn + * \- cpu_clk_dynX + * \- cpu_clk_dynX_sel + * \- cpu_clk_dynX_div + * \- xtal/fclk_div2/fclk_div3 + * \- xtal/fclk_div2/fclk_div3 + */ + + udelay(100); + + return NOTIFY_OK; + + case POST_RATE_CHANGE: + /* + * The sys_pll has ben updated, now switch back cpu_clk to + * sys_pll + */ + + /* Configure cpu_clk to use sys_pll */ + clk_hw_set_parent(nb_data->cpu_clk, + nb_data->sys_pll); + + udelay(100); + + /* new path : + * cpu_clk + * \- sys_pll + * \- sys_pll_dco + */ + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} + +static struct g12a_sys_pll_nb_data g12a_sys_pll_nb_data = { + .sys_pll = &g12a_sys_pll.hw, + .cpu_clk = &g12a_cpu_clk.hw, + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + +/* G12B first CPU cluster uses sys1_pll */ +static struct g12a_sys_pll_nb_data g12b_cpu_clk_sys1_pll_nb_data = { + .sys_pll = &g12b_sys1_pll.hw, + .cpu_clk = &g12b_cpu_clk.hw, + .cpu_clk_dyn = &g12a_cpu_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + +/* G12B second CPU cluster uses sys_pll */ +static struct g12a_sys_pll_nb_data g12b_cpub_clk_sys_pll_nb_data = { + .sys_pll = &g12a_sys_pll.hw, + .cpu_clk = &g12b_cpub_clk.hw, + .cpu_clk_dyn = &g12b_cpub_clk_dyn.hw, + .nb.notifier_call = g12a_sys_pll_notifier_cb, +}; + +static struct clk_regmap g12a_cpu_clk_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * G12A and G12B have different cpu clocks (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so this clock picks + * up the appropriate one. Same goes for the other + * clock using cpu cluster A clock output and present + * on both G12 variant. + */ + .name = "cpu_clk", + .index = -1, + }, + .num_parents = 1, + /* + * This clock is used to debug the cpu_clk range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12b_cpub_clk_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_div16_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + /* + * This clock is used to debug the cpu_clk range + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_fixed_factor g12a_cpu_clk_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div16", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_div16_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div16 = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div16", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_div16_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_apb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 3, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_apb_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .name = "cpu_clk", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_apb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_apb", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_apb_div.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_atb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 6, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_atb_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .name = "cpu_clk", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_atb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 17, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_atb", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_atb_div.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_axi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 9, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_axi_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .name = "cpu_clk", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_axi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 18, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_axi", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_axi_div.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12a_cpu_clk_trace_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 20, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_trace_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .name = "cpu_clk", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_cpu_clk_trace = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpu_clk_trace", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cpu_clk_trace_div.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div3", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div5 = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div5", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div7 = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div7", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12b_cpub_clk_div8 = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_div8", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk.hw + }, + .num_parents = 1, + }, +}; + +static u32 g12b_cpub_clk_if_parents_val_table[] = { 1, 2, 3, 4, 5, 6, 7 }; +static const struct clk_hw *g12b_cpub_clk_if_parents[] = { + &g12b_cpub_clk_div2.hw, + &g12b_cpub_clk_div3.hw, + &g12b_cpub_clk_div4.hw, + &g12b_cpub_clk_div5.hw, + &g12b_cpub_clk_div6.hw, + &g12b_cpub_clk_div7.hw, + &g12b_cpub_clk_div8.hw, +}; + +static struct clk_regmap g12b_cpub_clk_apb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .mask = 7, + .shift = 3, + .table = g12b_cpub_clk_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_apb_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), + }, +}; + +static struct clk_regmap g12b_cpub_clk_apb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 16, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_apb", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_apb_sel.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12b_cpub_clk_atb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .mask = 7, + .shift = 6, + .table = g12b_cpub_clk_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_atb_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), + }, +}; + +static struct clk_regmap g12b_cpub_clk_atb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 17, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_atb", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_atb_sel.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12b_cpub_clk_axi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .mask = 7, + .shift = 9, + .table = g12b_cpub_clk_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_axi_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), + }, +}; + +static struct clk_regmap g12b_cpub_clk_axi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 18, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_axi", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_axi_sel.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static struct clk_regmap g12b_cpub_clk_trace_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .mask = 7, + .shift = 20, + .table = g12b_cpub_clk_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpub_clk_trace_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = g12b_cpub_clk_if_parents, + .num_parents = ARRAY_SIZE(g12b_cpub_clk_if_parents), + }, +}; + +static struct clk_regmap g12b_cpub_clk_trace = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPUB_CLK_CNTL1, + .bit_idx = 23, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data) { + .name = "cpub_clk_trace", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_cpub_clk_trace_sel.hw + }, + .num_parents = 1, + /* + * This clock is set by the ROM monitor code, + * Linux should not change it at runtime + */ + }, +}; + +static const struct reg_sequence g12a_mpll0_init_regs[] = { + { .reg = HHI_MPLL_CNTL2, .def = 0x40000033 }, +}; + +static struct clk_regmap g12a_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 29, + .width = 1, + }, + .init_regs = g12a_mpll0_init_regs, + .init_count = ARRAY_SIZE(g12a_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence g12a_mpll1_init_regs[] = { + { .reg = HHI_MPLL_CNTL4, .def = 0x40000033 }, +}; + +static struct clk_regmap g12a_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 29, + .width = 1, + }, + .init_regs = g12a_mpll1_init_regs, + .init_count = ARRAY_SIZE(g12a_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence g12a_mpll2_init_regs[] = { + { .reg = HHI_MPLL_CNTL6, .def = 0x40000033 }, +}; + +static struct clk_regmap g12a_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 29, + .width = 1, + }, + .init_regs = g12a_mpll2_init_regs, + .init_count = ARRAY_SIZE(g12a_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence g12a_mpll3_init_regs[] = { + { .reg = HHI_MPLL_CNTL8, .def = 0x40000033 }, +}; + +static struct clk_regmap g12a_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 29, + .width = 1, + }, + .init_regs = g12a_mpll3_init_regs, + .init_count = ARRAY_SIZE(g12a_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* clk81 is often referred as "mpeg_clk" */ +static u32 g12a_clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data g12a_clk81_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div7.hw }, + { .hw = &g12a_mpll1.hw }, + { .hw = &g12a_mpll2.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, +}; + +static struct clk_regmap g12a_clk81_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = g12a_clk81_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = g12a_clk81_parents, + .num_parents = ARRAY_SIZE(g12a_clk81_parents), + }, +}; + +static struct clk_regmap g12a_clk81_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_clk81_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_clk81_div.hw + }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, +}; + +static const struct clk_parent_data g12a_sd_emmc_clk0_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be achieved using + * g12a_ee_core or fclk_div clocks + */ +}; + +/* SDIO clock */ +static struct clk_regmap g12a_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_a_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_a_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* SDcard clock */ +static struct clk_regmap g12a_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_b_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_b_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_regmap g12a_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_c_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_sd_emmc_c_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Video Clocks */ + +static struct clk_regmap g12a_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + .ops = &meson_vid_pll_div_ro_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_pll.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct clk_hw *g12a_vid_pll_parents[] = { + &g12a_vid_pll_div.hw, + &g12a_hdmi_pll.hw, +}; + +static struct clk_regmap g12a_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 18 selects from 2 possible parents: + * vid_pll_div or hdmi_pll + */ + .parent_hws = g12a_vid_pll_parents, + .num_parents = ARRAY_SIZE(g12a_vid_pll_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* VPU Clock */ + +static const struct clk_hw *g12a_vpu_parents[] = { + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_mpll1.hw, + &g12a_vid_pll.hw, + &g12a_hifi_pll.hw, + &g12a_gp0_pll.hw, +}; + +static struct clk_regmap g12a_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vpu_parents, + .num_parents = ARRAY_SIZE(g12a_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vpu_parents, + .num_parents = ARRAY_SIZE(g12a_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ + .parent_hws = (const struct clk_hw *[]) { + &g12a_vpu_0.hw, + &g12a_vpu_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VDEC clocks */ + +static const struct clk_hw *g12a_vdec_parents[] = { + &g12a_fclk_div2p5.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_hifi_pll.hw, + &g12a_gp0_pll.hw, +}; + +static struct clk_regmap g12a_vdec_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevcf_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevcf_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevcf = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevcf", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevcf_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vdec_parents, + .num_parents = ARRAY_SIZE(g12a_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vdec_hevc = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vdec_hevc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VAPB Clock */ + +static const struct clk_hw *g12a_vapb_parents[] = { + &g12a_fclk_div4.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, + &g12a_mpll1.hw, + &g12a_vid_pll.hw, + &g12a_mpll2.hw, + &g12a_fclk_div2p5.hw, +}; + +static struct clk_regmap g12a_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vapb_parents, + .num_parents = ARRAY_SIZE(g12a_vapb_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vapb_parents, + .num_parents = ARRAY_SIZE(g12a_vapb_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ + .parent_hws = (const struct clk_hw *[]) { + &g12a_vapb_0.hw, + &g12a_vapb_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static const struct clk_hw *g12a_vclk_parents[] = { + &g12a_vid_pll.hw, + &g12a_gp0_pll.hw, + &g12a_hifi_pll.hw, + &g12a_mpll1.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div4.hw, + &g12a_fclk_div5.hw, + &g12a_fclk_div7.hw, +}; + +static struct clk_regmap g12a_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vclk_parents, + .num_parents = ARRAY_SIZE(g12a_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_vclk_parents, + .num_parents = ARRAY_SIZE(g12a_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_sel.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_vclk2_div = { + .data = &(struct meson_vclk_div_data){ + .div = { + .reg_off = HHI_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .enable = { + .reg_off = HHI_VIID_CLK_DIV, + .shift = 16, + .width = 1, + }, + .reset = { + .reg_off = HHI_VIID_CLK_DIV, + .shift = 17, + .width = 1, + }, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &meson_vclk_div_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE, + }, +}; + +static struct clk_regmap g12a_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk2 = { + .data = &(struct meson_vclk_gate_data){ + .enable = { + .reg_off = HHI_VIID_CLK_CNTL, + .shift = 19, + .width = 1, + }, + .reset = { + .reg_off = HHI_VIID_CLK_CNTL, + .shift = 15, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &meson_vclk_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div4_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div6_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_vclk2_div12_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 g12a_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *g12a_cts_parents[] = { + &g12a_vclk_div1.hw, + &g12a_vclk_div2.hw, + &g12a_vclk_div4.hw, + &g12a_vclk_div6.hw, + &g12a_vclk_div12.hw, + &g12a_vclk2_div1.hw, + &g12a_vclk2_div2.hw, + &g12a_vclk2_div4.hw, + &g12a_vclk2_div6.hw, + &g12a_vclk2_div12.hw, +}; + +static struct clk_regmap g12a_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = g12a_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + .table = g12a_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = g12a_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_cts_vdac_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = g12a_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parents, + .num_parents = ARRAY_SIZE(g12a_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +/* TOFIX: add support for cts_tcon */ +static u32 g12a_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *g12a_hdmi_tx_parents[] = { + &g12a_vclk_div1.hw, + &g12a_vclk_div2.hw, + &g12a_vclk_div4.hw, + &g12a_vclk_div6.hw, + &g12a_vclk_div12.hw, + &g12a_vclk2_div1.hw, + &g12a_vclk2_div2.hw, + &g12a_vclk2_div4.hw, + &g12a_vclk2_div6.hw, + &g12a_vclk2_div12.hw, +}; + +static struct clk_regmap g12a_hdmi_tx_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + .table = g12a_hdmi_tx_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(g12a_hdmi_tx_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_enci_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_encp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_cts_vdac = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_vdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_hdmi_tx = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_hdmi_tx_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* MIPI DSI Host Clocks */ + +static const struct clk_hw *g12a_mipi_dsi_pxclk_parents[] = { + &g12a_vid_pll.hw, + &g12a_gp0_pll.hw, + &g12a_hifi_pll.hw, + &g12a_mpll1.hw, + &g12a_fclk_div2.hw, + &g12a_fclk_div2p5.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div7.hw, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_mipi_dsi_pxclk_parents, + .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + }, +}; + +/* + * FIXME: Force as bypass by forcing a single /1 table entry, and doesn't on boot value + * when setting a clock with this node in the clock path, but doesn't guarantee the divider + * is at /1 at boot until a rate is set. + */ +static const struct clk_div_table g12a_mipi_dsi_pxclk_div_table[] = { + { .val = 0, .div = 1 }, + { /* sentinel */ }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .shift = 0, + .width = 7, + .table = g12a_mipi_dsi_pxclk_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_dsi_pxclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* MIPI ISP Clocks */ + +static const struct clk_parent_data g12b_mipi_isp_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw }, + { .hw = &g12a_hifi_pll.hw }, + { .hw = &g12a_fclk_div2p5.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12b_mipi_isp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_ISP_CLK_CNTL, + .mask = 7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12b_mipi_isp_parents, + .num_parents = ARRAY_SIZE(g12b_mipi_isp_parents), + }, +}; + +static struct clk_regmap g12b_mipi_isp_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_ISP_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12b_mipi_isp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_ISP_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_isp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* HDMI Clocks */ + +static const struct clk_parent_data g12a_hdmi_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div5.hw }, +}; + +static struct clk_regmap g12a_hdmi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_hdmi_parents, + .num_parents = ARRAY_SIZE(g12a_hdmi_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_hdmi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_hdmi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_HDMI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &g12a_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. The CCF can manage this glitch-free + * mux because it does top-to-bottom updates the each clock tree and + * switches to the "inactive" one when CLK_SET_RATE_GATE is set. + */ +static const struct clk_parent_data g12a_mali_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw }, + { .hw = &g12a_hifi_pll.hw }, + { .hw = &g12a_fclk_div2p5.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12a_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_mali_parents, + .num_parents = ARRAY_SIZE(g12a_mali_parents), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the MPLL clocks for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap g12a_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_mali_parents, + .num_parents = ARRAY_SIZE(g12a_mali_parents), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the MPLL clocks for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap g12a_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mali_0.hw, + &g12a_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_ts_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_TS_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_ts = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_TS_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_ts_div.hw + }, + .num_parents = 1, + }, +}; + +/* SPICC SCLK source clock */ + +static const struct clk_parent_data g12a_spicc_sclk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_clk81.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div2.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12a_spicc0_sclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SPICC_CLK_CNTL, + .mask = 7, + .shift = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_spicc_sclk_parents, + .num_parents = ARRAY_SIZE(g12a_spicc_sclk_parents), + }, +}; + +static struct clk_regmap g12a_spicc0_sclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SPICC_CLK_CNTL, + .shift = 0, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc0_sclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc0_sclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SPICC_CLK_CNTL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_sclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc0_sclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc1_sclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SPICC_CLK_CNTL, + .mask = 7, + .shift = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12a_spicc_sclk_parents, + .num_parents = ARRAY_SIZE(g12a_spicc_sclk_parents), + }, +}; + +static struct clk_regmap g12a_spicc1_sclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SPICC_CLK_CNTL, + .shift = 16, + .width = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc1_sclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_spicc1_sclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SPICC_CLK_CNTL, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc1_sclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_spicc1_sclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Neural Network Accelerator source clock */ + +static const struct clk_parent_data sm1_nna_clk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw, }, + { .hw = &g12a_hifi_pll.hw, }, + { .hw = &g12a_fclk_div2p5.hw, }, + { .hw = &g12a_fclk_div3.hw, }, + { .hw = &g12a_fclk_div4.hw, }, + { .hw = &g12a_fclk_div5.hw, }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap sm1_nna_axi_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NNA_CLK_CNTL, + .mask = 7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_axi_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = sm1_nna_clk_parents, + .num_parents = ARRAY_SIZE(sm1_nna_clk_parents), + }, +}; + +static struct clk_regmap sm1_nna_axi_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NNA_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_axi_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_nna_axi_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_nna_axi_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NNA_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_axi_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_nna_axi_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_nna_core_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NNA_CLK_CNTL, + .mask = 7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_core_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = sm1_nna_clk_parents, + .num_parents = ARRAY_SIZE(sm1_nna_clk_parents), + }, +}; + +static struct clk_regmap sm1_nna_core_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NNA_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_core_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_nna_core_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap sm1_nna_core_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NNA_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "nna_core_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &sm1_nna_core_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data g12a_pclk_parents = { .hw = &g12a_clk81.hw }; + +#define G12A_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &g12a_pclk_parents, _flags) + +#define G12A_PCLK_RO(_name, _reg, _bit, _flags) \ + MESON_PCLK_RO(_name, _reg, _bit, &g12a_pclk_parents, _flags) + +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static G12A_PCLK(g12a_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_locker, HHI_GCLK_MPEG0, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_eth_phy, HHI_GCLK_MPEG0, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_spicc_0, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_sana, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_sd, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_spicc_1, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_hiu_reg, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_a, HHI_GCLK_MPEG0, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_codec, HHI_GCLK_MPEG0, 28, CLK_IGNORE_UNUSED); + +static G12A_PCLK(g12a_audio, HHI_GCLK_MPEG1, 0, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_eth_core, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_audio_ififo, HHI_GCLK_MPEG1, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_adc, HHI_GCLK_MPEG1, 13, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pcie_comb, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_usb_general, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_pcie_phy, HHI_GCLK_MPEG1, 27, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); + +static G12A_PCLK(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_htx_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_bt656, HHI_GCLK_MPEG2, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_csi_phy1, HHI_GCLK_MPEG2, 28, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12b_csi_phy0, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_gic, HHI_GCLK_MPEG2, 30, CLK_IGNORE_UNUSED); + +static G12A_PCLK(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_other, HHI_GCLK_OTHER, 7, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_enci, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_encp, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_enct, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_encl, HHI_GCLK_OTHER, 23, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static G12A_PCLK(g12a_vclk2_other1, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); + +static G12A_PCLK_RO(g12a_dma, HHI_GCLK_OTHER2, 0, 0); +static G12A_PCLK_RO(g12a_efuse, HHI_GCLK_OTHER2, 1, 0); +static G12A_PCLK_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2, 0); +static G12A_PCLK_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3, 0); +static G12A_PCLK_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4, 0); + +/* Array of all clocks provided by this provider */ +static struct clk_hw *g12a_hw_clks[] = { + [CLKID_SYS_PLL] = &g12a_sys_pll.hw, + [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, + [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, + [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, + [CLKID_CLK81] = &g12a_clk81.hw, + [CLKID_MPLL0] = &g12a_mpll0.hw, + [CLKID_MPLL1] = &g12a_mpll1.hw, + [CLKID_MPLL2] = &g12a_mpll2.hw, + [CLKID_MPLL3] = &g12a_mpll3.hw, + [CLKID_DDR] = &g12a_ddr.hw, + [CLKID_DOS] = &g12a_dos.hw, + [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, + [CLKID_ETH_PHY] = &g12a_eth_phy.hw, + [CLKID_ISA] = &g12a_isa.hw, + [CLKID_PL301] = &g12a_pl301.hw, + [CLKID_PERIPHS] = &g12a_periphs.hw, + [CLKID_SPICC0] = &g12a_spicc_0.hw, + [CLKID_I2C] = &g12a_i2c.hw, + [CLKID_SANA] = &g12a_sana.hw, + [CLKID_SD] = &g12a_sd.hw, + [CLKID_RNG0] = &g12a_rng0.hw, + [CLKID_UART0] = &g12a_uart0.hw, + [CLKID_SPICC1] = &g12a_spicc_1.hw, + [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, + [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, + [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, + [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, + [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, + [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, + [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, + [CLKID_AUDIO] = &g12a_audio.hw, + [CLKID_ETH] = &g12a_eth_core.hw, + [CLKID_DEMUX] = &g12a_demux.hw, + [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, + [CLKID_ADC] = &g12a_adc.hw, + [CLKID_UART1] = &g12a_uart1.hw, + [CLKID_G2D] = &g12a_g2d.hw, + [CLKID_RESET] = &g12a_reset.hw, + [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, + [CLKID_PARSER] = &g12a_parser.hw, + [CLKID_USB] = &g12a_usb_general.hw, + [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, + [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, + [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, + [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, + [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, + [CLKID_BT656] = &g12a_bt656.hw, + [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, + [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, + [CLKID_UART2] = &g12a_uart2.hw, + [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, + [CLKID_GIC] = &g12a_gic.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, + [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, + [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, + [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, + [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, + [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, + [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, + [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, + [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, + [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, + [CLKID_DAC_CLK] = &g12a_dac_clk.hw, + [CLKID_AOCLK] = &g12a_aoclk_gate.hw, + [CLKID_IEC958] = &g12a_iec958_gate.hw, + [CLKID_ENC480P] = &g12a_enc480p.hw, + [CLKID_RNG1] = &g12a_rng1.hw, + [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, + [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, + [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, + [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, + [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, + [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, + [CLKID_DMA] = &g12a_dma.hw, + [CLKID_EFUSE] = &g12a_efuse.hw, + [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, + [CLKID_RESET_SEC] = &g12a_reset_sec.hw, + [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, + [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, + [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, + [CLKID_VPU_0] = &g12a_vpu_0.hw, + [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, + [CLKID_VPU_1] = &g12a_vpu_1.hw, + [CLKID_VPU] = &g12a_vpu.hw, + [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, + [CLKID_VAPB_0] = &g12a_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, + [CLKID_VAPB_1] = &g12a_vapb_1.hw, + [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, + [CLKID_VAPB] = &g12a_vapb.hw, + [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, + [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, + [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, + [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, + [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, + [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, + [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, + [CLKID_VCLK] = &g12a_vclk.hw, + [CLKID_VCLK2] = &g12a_vclk2.hw, + [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, + [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, + [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, + [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, + [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, + [CLKID_HDMI] = &g12a_hdmi.hw, + [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, + [CLKID_MALI_0] = &g12a_mali_0.hw, + [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, + [CLKID_MALI_1] = &g12a_mali_1.hw, + [CLKID_MALI] = &g12a_mali.hw, + [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, + [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, + [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, + [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, + [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, + [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, + [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, + [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, + [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, + [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, + [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, + [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, + [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, + [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, + [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, + [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, + [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, + [CLKID_VDEC_1] = &g12a_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, + [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, + [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, + [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, + [CLKID_TS_DIV] = &g12a_ts_div.hw, + [CLKID_TS] = &g12a_ts.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, +}; + +static struct clk_hw *g12b_hw_clks[] = { + [CLKID_SYS_PLL] = &g12a_sys_pll.hw, + [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, + [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, + [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, + [CLKID_CLK81] = &g12a_clk81.hw, + [CLKID_MPLL0] = &g12a_mpll0.hw, + [CLKID_MPLL1] = &g12a_mpll1.hw, + [CLKID_MPLL2] = &g12a_mpll2.hw, + [CLKID_MPLL3] = &g12a_mpll3.hw, + [CLKID_DDR] = &g12a_ddr.hw, + [CLKID_DOS] = &g12a_dos.hw, + [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, + [CLKID_ETH_PHY] = &g12a_eth_phy.hw, + [CLKID_ISA] = &g12a_isa.hw, + [CLKID_PL301] = &g12a_pl301.hw, + [CLKID_PERIPHS] = &g12a_periphs.hw, + [CLKID_SPICC0] = &g12a_spicc_0.hw, + [CLKID_I2C] = &g12a_i2c.hw, + [CLKID_SANA] = &g12a_sana.hw, + [CLKID_SD] = &g12a_sd.hw, + [CLKID_RNG0] = &g12a_rng0.hw, + [CLKID_UART0] = &g12a_uart0.hw, + [CLKID_SPICC1] = &g12a_spicc_1.hw, + [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, + [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, + [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, + [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, + [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, + [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, + [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, + [CLKID_AUDIO] = &g12a_audio.hw, + [CLKID_ETH] = &g12a_eth_core.hw, + [CLKID_DEMUX] = &g12a_demux.hw, + [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, + [CLKID_ADC] = &g12a_adc.hw, + [CLKID_UART1] = &g12a_uart1.hw, + [CLKID_G2D] = &g12a_g2d.hw, + [CLKID_RESET] = &g12a_reset.hw, + [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, + [CLKID_PARSER] = &g12a_parser.hw, + [CLKID_USB] = &g12a_usb_general.hw, + [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, + [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, + [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, + [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, + [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, + [CLKID_BT656] = &g12a_bt656.hw, + [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, + [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, + [CLKID_UART2] = &g12a_uart2.hw, + [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, + [CLKID_GIC] = &g12a_gic.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, + [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, + [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, + [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, + [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, + [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, + [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, + [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, + [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, + [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, + [CLKID_DAC_CLK] = &g12a_dac_clk.hw, + [CLKID_AOCLK] = &g12a_aoclk_gate.hw, + [CLKID_IEC958] = &g12a_iec958_gate.hw, + [CLKID_ENC480P] = &g12a_enc480p.hw, + [CLKID_RNG1] = &g12a_rng1.hw, + [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, + [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, + [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, + [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, + [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, + [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, + [CLKID_DMA] = &g12a_dma.hw, + [CLKID_EFUSE] = &g12a_efuse.hw, + [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, + [CLKID_RESET_SEC] = &g12a_reset_sec.hw, + [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, + [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, + [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, + [CLKID_VPU_0] = &g12a_vpu_0.hw, + [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, + [CLKID_VPU_1] = &g12a_vpu_1.hw, + [CLKID_VPU] = &g12a_vpu.hw, + [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, + [CLKID_VAPB_0] = &g12a_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, + [CLKID_VAPB_1] = &g12a_vapb_1.hw, + [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, + [CLKID_VAPB] = &g12a_vapb.hw, + [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, + [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, + [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, + [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, + [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, + [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, + [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, + [CLKID_VCLK] = &g12a_vclk.hw, + [CLKID_VCLK2] = &g12a_vclk2.hw, + [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, + [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, + [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, + [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, + [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, + [CLKID_HDMI] = &g12a_hdmi.hw, + [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, + [CLKID_MALI_0] = &g12a_mali_0.hw, + [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, + [CLKID_MALI_1] = &g12a_mali_1.hw, + [CLKID_MALI] = &g12a_mali.hw, + [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, + [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, + [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, + [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, + [CLKID_CPU_CLK] = &g12b_cpu_clk.hw, + [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, + [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, + [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, + [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, + [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, + [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, + [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, + [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, + [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, + [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, + [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, + [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, + [CLKID_VDEC_1] = &g12a_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, + [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, + [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, + [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, + [CLKID_TS_DIV] = &g12a_ts_div.hw, + [CLKID_TS] = &g12a_ts.hw, + [CLKID_SYS1_PLL_DCO] = &g12b_sys1_pll_dco.hw, + [CLKID_SYS1_PLL] = &g12b_sys1_pll.hw, + [CLKID_SYS1_PLL_DIV16_EN] = &g12b_sys1_pll_div16_en.hw, + [CLKID_SYS1_PLL_DIV16] = &g12b_sys1_pll_div16.hw, + [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_dyn0_sel.hw, + [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_dyn0_div.hw, + [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_dyn0.hw, + [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_dyn1_sel.hw, + [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_dyn1_div.hw, + [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_dyn1.hw, + [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw, + [CLKID_CPUB_CLK] = &g12b_cpub_clk.hw, + [CLKID_CPUB_CLK_DIV16_EN] = &g12b_cpub_clk_div16_en.hw, + [CLKID_CPUB_CLK_DIV16] = &g12b_cpub_clk_div16.hw, + [CLKID_CPUB_CLK_DIV2] = &g12b_cpub_clk_div2.hw, + [CLKID_CPUB_CLK_DIV3] = &g12b_cpub_clk_div3.hw, + [CLKID_CPUB_CLK_DIV4] = &g12b_cpub_clk_div4.hw, + [CLKID_CPUB_CLK_DIV5] = &g12b_cpub_clk_div5.hw, + [CLKID_CPUB_CLK_DIV6] = &g12b_cpub_clk_div6.hw, + [CLKID_CPUB_CLK_DIV7] = &g12b_cpub_clk_div7.hw, + [CLKID_CPUB_CLK_DIV8] = &g12b_cpub_clk_div8.hw, + [CLKID_CPUB_CLK_APB_SEL] = &g12b_cpub_clk_apb_sel.hw, + [CLKID_CPUB_CLK_APB] = &g12b_cpub_clk_apb.hw, + [CLKID_CPUB_CLK_ATB_SEL] = &g12b_cpub_clk_atb_sel.hw, + [CLKID_CPUB_CLK_ATB] = &g12b_cpub_clk_atb.hw, + [CLKID_CPUB_CLK_AXI_SEL] = &g12b_cpub_clk_axi_sel.hw, + [CLKID_CPUB_CLK_AXI] = &g12b_cpub_clk_axi.hw, + [CLKID_CPUB_CLK_TRACE_SEL] = &g12b_cpub_clk_trace_sel.hw, + [CLKID_CPUB_CLK_TRACE] = &g12b_cpub_clk_trace.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_NNA_AXI_CLK_SEL] = &sm1_nna_axi_clk_sel.hw, + [CLKID_NNA_AXI_CLK_DIV] = &sm1_nna_axi_clk_div.hw, + [CLKID_NNA_AXI_CLK] = &sm1_nna_axi_clk.hw, + [CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw, + [CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw, + [CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, + [CLKID_MIPI_ISP_SEL] = &g12b_mipi_isp_sel.hw, + [CLKID_MIPI_ISP_DIV] = &g12b_mipi_isp_div.hw, + [CLKID_MIPI_ISP] = &g12b_mipi_isp.hw, + [CLKID_MIPI_ISP_GATE] = &g12b_mipi_isp_gate.hw, + [CLKID_MIPI_ISP_CSI_PHY0] = &g12b_csi_phy0.hw, + [CLKID_MIPI_ISP_CSI_PHY1] = &g12b_csi_phy1.hw, +}; + +static struct clk_hw *sm1_hw_clks[] = { + [CLKID_SYS_PLL] = &g12a_sys_pll.hw, + [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, + [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, + [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, + [CLKID_MPEG_SEL] = &g12a_clk81_sel.hw, + [CLKID_MPEG_DIV] = &g12a_clk81_div.hw, + [CLKID_CLK81] = &g12a_clk81.hw, + [CLKID_MPLL0] = &g12a_mpll0.hw, + [CLKID_MPLL1] = &g12a_mpll1.hw, + [CLKID_MPLL2] = &g12a_mpll2.hw, + [CLKID_MPLL3] = &g12a_mpll3.hw, + [CLKID_DDR] = &g12a_ddr.hw, + [CLKID_DOS] = &g12a_dos.hw, + [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, + [CLKID_ETH_PHY] = &g12a_eth_phy.hw, + [CLKID_ISA] = &g12a_isa.hw, + [CLKID_PL301] = &g12a_pl301.hw, + [CLKID_PERIPHS] = &g12a_periphs.hw, + [CLKID_SPICC0] = &g12a_spicc_0.hw, + [CLKID_I2C] = &g12a_i2c.hw, + [CLKID_SANA] = &g12a_sana.hw, + [CLKID_SD] = &g12a_sd.hw, + [CLKID_RNG0] = &g12a_rng0.hw, + [CLKID_UART0] = &g12a_uart0.hw, + [CLKID_SPICC1] = &g12a_spicc_1.hw, + [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, + [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, + [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, + [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, + [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, + [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, + [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, + [CLKID_AUDIO] = &g12a_audio.hw, + [CLKID_ETH] = &g12a_eth_core.hw, + [CLKID_DEMUX] = &g12a_demux.hw, + [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, + [CLKID_ADC] = &g12a_adc.hw, + [CLKID_UART1] = &g12a_uart1.hw, + [CLKID_G2D] = &g12a_g2d.hw, + [CLKID_RESET] = &g12a_reset.hw, + [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, + [CLKID_PARSER] = &g12a_parser.hw, + [CLKID_USB] = &g12a_usb_general.hw, + [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, + [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, + [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, + [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, + [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, + [CLKID_BT656] = &g12a_bt656.hw, + [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, + [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, + [CLKID_UART2] = &g12a_uart2.hw, + [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, + [CLKID_GIC] = &g12a_gic.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, + [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, + [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, + [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, + [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, + [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, + [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, + [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, + [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, + [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, + [CLKID_DAC_CLK] = &g12a_dac_clk.hw, + [CLKID_AOCLK] = &g12a_aoclk_gate.hw, + [CLKID_IEC958] = &g12a_iec958_gate.hw, + [CLKID_ENC480P] = &g12a_enc480p.hw, + [CLKID_RNG1] = &g12a_rng1.hw, + [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, + [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, + [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, + [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, + [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, + [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, + [CLKID_DMA] = &g12a_dma.hw, + [CLKID_EFUSE] = &g12a_efuse.hw, + [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, + [CLKID_RESET_SEC] = &g12a_reset_sec.hw, + [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, + [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, + [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, + [CLKID_VPU_0] = &g12a_vpu_0.hw, + [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, + [CLKID_VPU_1] = &g12a_vpu_1.hw, + [CLKID_VPU] = &g12a_vpu.hw, + [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, + [CLKID_VAPB_0] = &g12a_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, + [CLKID_VAPB_1] = &g12a_vapb_1.hw, + [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, + [CLKID_VAPB] = &g12a_vapb.hw, + [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, + [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, + [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, + [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, + [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, + [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, + [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, + [CLKID_VCLK] = &g12a_vclk.hw, + [CLKID_VCLK2] = &g12a_vclk2.hw, + [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, + [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, + [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, + [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, + [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, + [CLKID_HDMI] = &g12a_hdmi.hw, + [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, + [CLKID_MALI_0] = &g12a_mali_0.hw, + [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, + [CLKID_MALI_1] = &g12a_mali_1.hw, + [CLKID_MALI] = &g12a_mali.hw, + [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, + [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, + [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_dyn0_sel.hw, + [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_dyn0_div.hw, + [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_dyn0.hw, + [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_dyn1_sel.hw, + [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_dyn1_div.hw, + [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_dyn1.hw, + [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, + [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, + [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, + [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, + [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, + [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, + [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, + [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, + [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, + [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, + [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, + [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, + [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, + [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, + [CLKID_VDEC_1] = &g12a_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, + [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, + [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, + [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, + [CLKID_TS_DIV] = &g12a_ts_div.hw, + [CLKID_TS] = &g12a_ts.hw, + [CLKID_GP1_PLL_DCO] = &sm1_gp1_pll_dco.hw, + [CLKID_GP1_PLL] = &sm1_gp1_pll.hw, + [CLKID_DSU_CLK_DYN0_SEL] = &sm1_dsu_clk_dyn0_sel.hw, + [CLKID_DSU_CLK_DYN0_DIV] = &sm1_dsu_clk_dyn0_div.hw, + [CLKID_DSU_CLK_DYN0] = &sm1_dsu_clk_dyn0.hw, + [CLKID_DSU_CLK_DYN1_SEL] = &sm1_dsu_clk_dyn1_sel.hw, + [CLKID_DSU_CLK_DYN1_DIV] = &sm1_dsu_clk_dyn1_div.hw, + [CLKID_DSU_CLK_DYN1] = &sm1_dsu_clk_dyn1.hw, + [CLKID_DSU_CLK_DYN] = &sm1_dsu_clk_dyn.hw, + [CLKID_DSU_CLK_FINAL] = &sm1_dsu_final_clk.hw, + [CLKID_DSU_CLK] = &sm1_dsu_clk.hw, + [CLKID_CPU1_CLK] = &sm1_cpu1_clk.hw, + [CLKID_CPU2_CLK] = &sm1_cpu2_clk.hw, + [CLKID_CPU3_CLK] = &sm1_cpu3_clk.hw, + [CLKID_SPICC0_SCLK_SEL] = &g12a_spicc0_sclk_sel.hw, + [CLKID_SPICC0_SCLK_DIV] = &g12a_spicc0_sclk_div.hw, + [CLKID_SPICC0_SCLK] = &g12a_spicc0_sclk.hw, + [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, + [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, + [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_NNA_AXI_CLK_SEL] = &sm1_nna_axi_clk_sel.hw, + [CLKID_NNA_AXI_CLK_DIV] = &sm1_nna_axi_clk_div.hw, + [CLKID_NNA_AXI_CLK] = &sm1_nna_axi_clk.hw, + [CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw, + [CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw, + [CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, +}; + +static const struct reg_sequence g12a_init_regs[] = { + { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, +}; + +#define DVFS_CON_ID "dvfs" + +static int g12a_dvfs_setup_common(struct device *dev, struct clk_hw **hws) +{ + struct clk *notifier_clk; + struct clk_hw *xtal; + int ret; + + xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); + + /* Setup clock notifier for cpu_clk_postmux0 */ + g12a_cpu_clk_dyn0_nb_data.xtal = xtal; + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn0.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_dyn0_nb_data.nb); + if (ret) { + dev_err(dev, "failed to register the cpu_clk_dyn0 notifier\n"); + return ret; + } + + /* Setup clock notifier for cpu_clk_dyn mux */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk_dyn.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(dev, "failed to register the cpu_clk_dyn notifier\n"); + return ret; + } + + return 0; +} + +static int g12b_dvfs_setup(struct platform_device *pdev) +{ + struct clk_hw **hws = g12b_hw_clks; + struct device *dev = &pdev->dev; + struct clk *notifier_clk; + struct clk_hw *xtal; + int ret; + + ret = g12a_dvfs_setup_common(dev, hws); + if (ret) + return ret; + + xtal = clk_hw_get_parent_by_index(hws[CLKID_CPU_CLK_DYN1_SEL], 0); + + /* Setup clock notifier for cpu_clk mux */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpu_clk.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(dev, "failed to register the cpu_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys1_pll */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_sys1_pll.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpu_clk_sys1_pll_nb_data.nb); + if (ret) { + dev_err(dev, "failed to register the sys1_pll notifier\n"); + return ret; + } + + /* Add notifiers for the second CPU cluster */ + + /* Setup clock notifier for cpub_clk_postmux0 */ + g12b_cpub_clk_dyn0_nb_data.xtal = xtal; + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn0.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpub_clk_dyn0_nb_data.nb); + if (ret) { + dev_err(dev, "failed to register the cpub_clk_dyn0 notifier\n"); + return ret; + } + + /* Setup clock notifier for cpub_clk_dyn mux */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk_dyn.hw, + DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(dev, "failed to register the cpub_clk_dyn notifier\n"); + return ret; + } + + /* Setup clock notifier for cpub_clk mux */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12b_cpub_clk.hw, DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(dev, "failed to register the cpub_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys_pll */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12b_cpub_clk_sys_pll_nb_data.nb); + if (ret) { + dev_err(dev, "failed to register the sys_pll notifier\n"); + return ret; + } + + return 0; +} + +static int g12a_dvfs_setup(struct platform_device *pdev) +{ + struct clk_hw **hws = g12a_hw_clks; + struct device *dev = &pdev->dev; + struct clk *notifier_clk; + int ret; + + ret = g12a_dvfs_setup_common(dev, hws); + if (ret) + return ret; + + /* Setup clock notifier for cpu_clk mux */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_cpu_clk.hw, DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_cpu_clk_mux_nb); + if (ret) { + dev_err(dev, "failed to register the cpu_clk notifier\n"); + return ret; + } + + /* Setup clock notifier for sys_pll */ + notifier_clk = devm_clk_hw_get_clk(dev, &g12a_sys_pll.hw, DVFS_CON_ID); + ret = devm_clk_notifier_register(dev, notifier_clk, + &g12a_sys_pll_nb_data.nb); + if (ret) { + dev_err(dev, "failed to register the sys_pll notifier\n"); + return ret; + } + + return 0; +} + +struct g12a_clkc_data { + const struct meson_clkc_data clkc_data; + int (*dvfs_setup)(struct platform_device *pdev); +}; + +static int g12a_clkc_probe(struct platform_device *pdev) +{ + const struct meson_clkc_data *clkc_data; + const struct g12a_clkc_data *g12a_data; + int ret; + + clkc_data = of_device_get_match_data(&pdev->dev); + if (!clkc_data) + return -EINVAL; + + ret = meson_clkc_syscon_probe(pdev); + if (ret) + return ret; + + g12a_data = container_of(clkc_data, struct g12a_clkc_data, + clkc_data); + + if (g12a_data->dvfs_setup) + return g12a_data->dvfs_setup(pdev); + + return 0; +} + +static const struct g12a_clkc_data g12a_clkc_data = { + .clkc_data = { + .hw_clks = { + .hws = g12a_hw_clks, + .num = ARRAY_SIZE(g12a_hw_clks), + }, + .init_regs = g12a_init_regs, + .init_count = ARRAY_SIZE(g12a_init_regs), + }, + .dvfs_setup = g12a_dvfs_setup, +}; + +static const struct g12a_clkc_data g12b_clkc_data = { + .clkc_data = { + .hw_clks = { + .hws = g12b_hw_clks, + .num = ARRAY_SIZE(g12b_hw_clks), + }, + }, + .dvfs_setup = g12b_dvfs_setup, +}; + +static const struct g12a_clkc_data sm1_clkc_data = { + .clkc_data = { + .hw_clks = { + .hws = sm1_hw_clks, + .num = ARRAY_SIZE(sm1_hw_clks), + }, + }, + .dvfs_setup = g12a_dvfs_setup, +}; + +static const struct of_device_id g12a_clkc_match_table[] = { + { + .compatible = "amlogic,g12a-clkc", + .data = &g12a_clkc_data.clkc_data + }, + { + .compatible = "amlogic,g12b-clkc", + .data = &g12b_clkc_data.clkc_data + }, + { + .compatible = "amlogic,sm1-clkc", + .data = &sm1_clkc_data.clkc_data + }, + {} +}; +MODULE_DEVICE_TABLE(of, g12a_clkc_match_table); + +static struct platform_driver g12a_clkc_driver = { + .probe = g12a_clkc_probe, + .driver = { + .name = "g12a-clkc", + .of_match_table = g12a_clkc_match_table, + }, +}; +module_platform_driver(g12a_clkc_driver); + +MODULE_DESCRIPTION("Amlogic G12/SM1 Main Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c new file mode 100644 index 000000000..c7dfb3a06 --- /dev/null +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + */ +#include +#include +#include +#include "meson-aoclk.h" + +#include "clk-regmap.h" +#include "clk-dualdiv.h" + +#include +#include + +/* AO Configuration Clock registers offsets */ +#define AO_RTI_PWR_CNTL_REG1 0x0c +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + +static const struct clk_parent_data gxbb_ao_pclk_parents = { .fw_name = "mpeg-clk" }; + +#define GXBB_AO_PCLK(_name, _bit, _flags) \ + MESON_PCLK(gxbb_ao_##_name, AO_RTI_GEN_CNTL_REG0, _bit, \ + &gxbb_ao_pclk_parents, _flags) + +static GXBB_AO_PCLK(remote, 0, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(i2c_master, 1, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(i2c_slave, 2, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(uart1, 3, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(uart2, 5, CLK_IGNORE_UNUSED); +static GXBB_AO_PCLK(ir_blaster, 6, CLK_IGNORE_UNUSED); + +static struct clk_regmap gxbb_ao_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_ao_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_cts_oscin.hw }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap gxbb_ao_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = gxbb_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_32k_pre.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_ao_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_ao_32k_div.hw, + &gxbb_ao_32k_pre.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_ao_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_ao_32k_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_ao_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x7, + .shift = 10, + .table = (u32[]){ 1, 2, 3, 4 }, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "ext-32k-0", }, + { .fw_name = "ext-32k-1", }, + { .fw_name = "ext-32k-2", }, + { .hw = &gxbb_ao_32k.hw }, + }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_ao_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "mpeg-clk", }, + { .hw = &gxbb_ao_cts_rtc_oscin.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_ao_cts_cec = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CRT_CLK_CNTL1, + .mask = 0x1, + .shift = 27, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_cec", + .ops = &clk_regmap_mux_ops, + /* + * FIXME: The 'fixme' parent obviously does not exist. + * + * ATM, CCF won't call get_parent() if num_parents is 1. It + * does not allow NULL as a parent name either. + * + * On this particular mux, we only know the input #1 parent + * but, on boot, unknown input #0 is set, so it is critical + * to call .get_parent() on it + * + * Until CCF gets fixed, adding this fake parent that won't + * ever be registered should work around the problem + */ + .parent_data = (const struct clk_parent_data []) { + { .name = "fixme", .index = -1, }, + { .hw = &gxbb_ao_cts_rtc_oscin.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const unsigned int gxbb_ao_reset[] = { + [RESET_AO_REMOTE] = 16, + [RESET_AO_I2C_MASTER] = 18, + [RESET_AO_I2C_SLAVE] = 19, + [RESET_AO_UART1] = 17, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_BLASTER] = 23, +}; + +static struct clk_hw *gxbb_ao_hw_clks[] = { + [CLKID_AO_REMOTE] = &gxbb_ao_remote.hw, + [CLKID_AO_I2C_MASTER] = &gxbb_ao_i2c_master.hw, + [CLKID_AO_I2C_SLAVE] = &gxbb_ao_i2c_slave.hw, + [CLKID_AO_UART1] = &gxbb_ao_uart1.hw, + [CLKID_AO_UART2] = &gxbb_ao_uart2.hw, + [CLKID_AO_IR_BLASTER] = &gxbb_ao_ir_blaster.hw, + [CLKID_AO_CEC_32K] = &gxbb_ao_cts_cec.hw, + [CLKID_AO_CTS_OSCIN] = &gxbb_ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &gxbb_ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &gxbb_ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &gxbb_ao_32k_sel.hw, + [CLKID_AO_32K] = &gxbb_ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &gxbb_ao_cts_rtc_oscin.hw, + [CLKID_AO_CLK81] = &gxbb_ao_clk81.hw, +}; + +static const struct meson_aoclk_data gxbb_ao_clkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(gxbb_ao_reset), + .reset = gxbb_ao_reset, + .clkc_data = { + .hw_clks = { + .hws = gxbb_ao_hw_clks, + .num = ARRAY_SIZE(gxbb_ao_hw_clks), + }, + }, +}; + +static const struct of_device_id gxbb_ao_clkc_match_table[] = { + { + .compatible = "amlogic,meson-gx-aoclkc", + .data = &gxbb_ao_clkc_data.clkc_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, gxbb_ao_clkc_match_table); + +static struct platform_driver gxbb_ao_clkc_driver = { + .probe = meson_aoclkc_probe, + .driver = { + .name = "gxbb-aoclkc", + .of_match_table = gxbb_ao_clkc_match_table, + }, +}; +module_platform_driver(gxbb_ao_clkc_driver); + +MODULE_DESCRIPTION("Amlogic GXBB Always-ON Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c new file mode 100644 index 000000000..7a7b10418 --- /dev/null +++ b/drivers/clk/meson/gxbb.c @@ -0,0 +1,3297 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016 AmLogic, Inc. + * Michael Turquette + */ + +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" +#include "meson-clkc-utils.h" +#include "vid-pll-div.h" + +#include + +#define SCR 0x2c +#define TIMEOUT_VALUE 0x3c + +#define HHI_GP0_PLL_CNTL 0x40 +#define HHI_GP0_PLL_CNTL2 0x44 +#define HHI_GP0_PLL_CNTL3 0x48 +#define HHI_GP0_PLL_CNTL4 0x4c +#define HHI_GP0_PLL_CNTL5 0x50 +#define HHI_GP0_PLL_CNTL1 0x58 + +#define HHI_XTAL_DIVN_CNTL 0xbc +#define HHI_TIMER90K 0xec + +#define HHI_MEM_PD_REG0 0x100 +#define HHI_MEM_PD_REG1 0x104 +#define HHI_VPU_MEM_PD_REG1 0x108 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12c + +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_AO 0x154 +#define HHI_SYS_OSCIN_CNTL 0x158 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c +#define HHI_SYS_CPU_RESET_CNTL 0x160 +#define HHI_VID_CLK_DIV 0x164 + +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_AUD_CLK_CNTL 0x178 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_AUD_CLK_CNTL2 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_VID_PLL_CLK_DIV 0x1a0 +#define HHI_AUD_CLK_CNTL3 0x1a4 +#define HHI_MALI_CLK_CNTL 0x1b0 +#define HHI_VPU_CLK_CNTL 0x1bc + +#define HHI_HDMI_CLK_CNTL 0x1cc +#define HHI_VDEC_CLK_CNTL 0x1e0 +#define HHI_VDEC2_CLK_CNTL 0x1e4 +#define HHI_VDEC3_CLK_CNTL 0x1e8 +#define HHI_VDEC4_CLK_CNTL 0x1ec +#define HHI_HDCP22_CLK_CNTL 0x1f0 +#define HHI_VAPBCLK_CNTL 0x1f4 + +#define HHI_VPU_CLKB_CNTL 0x20c +#define HHI_USB_CLK_CNTL 0x220 +#define HHI_32K_CLK_CNTL 0x224 +#define HHI_GEN_CLK_CNTL 0x228 + +#define HHI_PCM_CLK_CNTL 0x258 +#define HHI_NAND_CLK_CNTL 0x25c +#define HHI_SD_EMMC_CLK_CNTL 0x264 + +#define HHI_MPLL_CNTL 0x280 +#define HHI_MPLL_CNTL2 0x284 +#define HHI_MPLL_CNTL3 0x288 +#define HHI_MPLL_CNTL4 0x28c +#define HHI_MPLL_CNTL5 0x290 +#define HHI_MPLL_CNTL6 0x294 +#define HHI_MPLL_CNTL7 0x298 +#define HHI_MPLL_CNTL8 0x29c +#define HHI_MPLL_CNTL9 0x2a0 +#define HHI_MPLL_CNTL10 0x2a4 + +#define HHI_MPLL3_CNTL0 0x2e0 +#define HHI_MPLL3_CNTL1 0x2e4 +#define HHI_VDAC_CNTL0 0x2f4 +#define HHI_VDAC_CNTL1 0x2f8 + +#define HHI_SYS_PLL_CNTL 0x300 +#define HHI_SYS_PLL_CNTL2 0x304 +#define HHI_SYS_PLL_CNTL3 0x308 +#define HHI_SYS_PLL_CNTL4 0x30c +#define HHI_SYS_PLL_CNTL5 0x310 +#define HHI_DPLL_TOP_I 0x318 +#define HHI_DPLL_TOP2_I 0x31c +#define HHI_HDMI_PLL_CNTL 0x320 +#define HHI_HDMI_PLL_CNTL2 0x324 +#define HHI_HDMI_PLL_CNTL3 0x328 +#define HHI_HDMI_PLL_CNTL4 0x32c +#define HHI_HDMI_PLL_CNTL5 0x330 +#define HHI_HDMI_PLL_CNTL6 0x334 +#define HHI_HDMI_PLL_CNTL_I 0x338 +#define HHI_HDMI_PLL_CNTL7 0x33c + +#define HHI_HDMI_PHY_CNTL0 0x3a0 +#define HHI_HDMI_PHY_CNTL1 0x3a4 +#define HHI_HDMI_PHY_CNTL2 0x3a8 +#define HHI_HDMI_PHY_CNTL3 0x3ac + +#define HHI_VID_LOCK_CLK_CNTL 0x3c8 +#define HHI_BT656_CLK_CNTL 0x3d4 +#define HHI_SAR_CLK_CNTL 0x3d8 + +static struct clk_regmap gxbb_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { + .mult = 2, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_pre_mult", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 28, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_pre_mult.hw + }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + /* + * On gxl, there is a register shift due to + * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, + * so we use the HHI_HDMI_PLL_CNTL2 define from GXBB + * instead which is defined at the same offset. + */ + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 0, + .width = 10, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 28, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_pll_od2.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +/* + * GXL hdmi OD dividers are POWER_OF_TWO dividers but limited to /4. + * A divider value of 3 should map to /8 but instead map /4 so ignore it. + */ +static const struct clk_div_table gxl_hdmi_pll_od_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { /* sentinel */ } +}; + +static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL3, + .shift = 21, + .width = 2, + .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL3, + .shift = 23, + .width = 2, + .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL3, + .shift = 19, + .width = 2, + .table = gxl_hdmi_pll_od_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxl_hdmi_pll_od2.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sys_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sys_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_params_table gxbb_gp0_pll_params_table[] = { + PLL_PARAMS(32, 1), + PLL_PARAMS(33, 1), + PLL_PARAMS(34, 1), + PLL_PARAMS(35, 1), + PLL_PARAMS(36, 1), + PLL_PARAMS(37, 1), + PLL_PARAMS(38, 1), + PLL_PARAMS(39, 1), + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + { /* sentinel */ }, +}; + +static const struct reg_sequence gxbb_gp0_pll_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, +}; + +static struct clk_regmap gxbb_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxbb_gp0_pll_params_table, + .init_regs = gxbb_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(gxbb_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static const struct pll_params_table gxl_gp0_pll_params_table[] = { + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + { /* sentinel */ }, +}; + +static const struct reg_sequence gxl_gp0_pll_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, +}; + +static struct clk_regmap gxl_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxl_gp0_pll_params_table, + .init_regs = gxl_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(gxl_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different gp0_pll_dco (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so gp0_pll picks up the + * appropriate one. + */ + .name = "gp0_pll_dco", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div2_div.hw + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div3_div.hw + }, + .num_parents = 1, + /* + * FIXME: + * This clock, as fdiv2, is used by the SCPI FW and is required + * by the platform to operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) The SCPI generic driver claims and enable all the clocks + * it needs + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxl_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different SDM_EN registers. We + * fallback to the global naming string mechanism so + * mpll0_div picks up the appropriate one. + */ + .name = "mpll0_div", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxbb_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* clk81 is often referred as "mpeg_clk" */ +static u32 clk81_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data clk81_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, +}; + +static struct clk_regmap gxbb_clk81_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = clk81_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_sel", + .ops = &clk_regmap_mux_ro_ops, + /* + * bits 14:12 selects from 8 possible parents: + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_data = clk81_parents, + .num_parents = ARRAY_SIZE(clk81_parents), + }, +}; + +static struct clk_regmap gxbb_clk81_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_clk81_sel.hw + }, + .num_parents = 1, + }, +}; + +/* the mother of dragons gates */ +static struct clk_regmap gxbb_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_clk81_div.hw + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap gxbb_sar_adc_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SAR_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "sar_adc_clk_sel", + .ops = &clk_regmap_mux_ops, + /* NOTE: The datasheet doesn't list the parents for bit 10 */ + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &gxbb_clk81.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap gxbb_sar_adc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SAR_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "sar_adc_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sar_adc_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sar_adc_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SAR_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "sar_adc_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sar_adc_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. The CCF can manage this glitch-free + * mux because it does top-to-bottom updates the each clock tree and + * switches to the "inactive" one when CLK_SET_RATE_GATE is set. + */ + +static const struct clk_parent_data gxbb_mali_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_gp0_pll.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, +}; + +static struct clk_regmap gxbb_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_mali_parents, + .num_parents = ARRAY_SIZE(gxbb_mali_parents), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the MPLL clocks for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap gxbb_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_mali_parents, + .num_parents = ARRAY_SIZE(gxbb_mali_parents), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the MPLL clocks for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap gxbb_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mali_0.hw, + &gxbb_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 gxbb_cts_mclk_parents_val_table[] = { 1, 2, 3 }; +static const struct clk_hw *gxbb_cts_mclk_parents[] = { + &gxbb_mpll0.hw, + &gxbb_mpll1.hw, + &gxbb_mpll2.hw, +}; + +static struct clk_regmap gxbb_cts_amclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .table = gxbb_cts_mclk_parents_val_table, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_cts_mclk_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_mclk_parents), + }, +}; + +static struct clk_regmap gxbb_cts_amclk_div = { + .data = &(struct clk_regmap_div_data) { + .offset = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_cts_amclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_cts_mclk_i958_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .table = gxbb_cts_mclk_parents_val_table, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_cts_mclk_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_mclk_parents), + }, +}; + +static struct clk_regmap gxbb_cts_mclk_i958_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_mclk_i958_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_cts_mclk_i958 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_mclk_i958_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_cts_i958 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_i958", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_amclk.hw, + &gxbb_cts_mclk_i958.hw + }, + .num_parents = 2, + /* + *The parent is specific to origin of the audio data. Let the + * consumer choose the appropriate parent + */ + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* + * This table skips a clock named 'cts_slow_oscin' in the documentation + * This clock does not exist yet in this controller or the AO one + */ +static u32 gxbb_32k_clk_parents_val_table[] = { 0, 2, 3 }; +static const struct clk_parent_data gxbb_32k_clk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, +}; + +static struct clk_regmap gxbb_32k_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_32K_CLK_CNTL, + .mask = 0x3, + .shift = 16, + .table = gxbb_32k_clk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "32k_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_32k_clk_parents, + .num_parents = ARRAY_SIZE(gxbb_32k_clk_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_32k_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_32K_CLK_CNTL, + .shift = 0, + .width = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "32k_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_32k_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_32k_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_32K_CLK_CNTL, + .bit_idx = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "32k_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_32k_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data gxbb_sd_emmc_clk0_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div2.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, + { .hw = &gxbb_fclk_div7.hw }, + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be achieved using + * xtal or fclk_div clocks + */ +}; + +/* SDIO clock */ +static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_a_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_a_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* SDcard clock */ +static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_b_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_b_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_c_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_sd_emmc_c_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VPU Clock */ + +static const struct clk_hw *gxbb_vpu_parents[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, +}; + +static struct clk_regmap gxbb_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_hws = gxbb_vpu_parents, + .num_parents = ARRAY_SIZE(gxbb_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap gxbb_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_hws = gxbb_vpu_parents, + .num_parents = ARRAY_SIZE(gxbb_vpu_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap gxbb_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vpu_0.hw, + &gxbb_vpu_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VAPB Clock */ + +static const struct clk_hw *gxbb_vapb_parents[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, +}; + +static struct clk_regmap gxbb_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_hws = gxbb_vapb_parents, + .num_parents = ARRAY_SIZE(gxbb_vapb_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap gxbb_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_hws = gxbb_vapb_parents, + .num_parents = ARRAY_SIZE(gxbb_vapb_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap gxbb_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vapb_0.hw, + &gxbb_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap gxbb_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vapb_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* Video Clocks */ + +static struct clk_regmap gxbb_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = HHI_VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + .ops = &meson_vid_pll_div_ro_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different hdmi_plls (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vid_pll_div picks up the + * appropriate one. + */ + .name = "hdmi_pll", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static const struct clk_parent_data gxbb_vid_pll_parents[] = { + { .hw = &gxbb_vid_pll_div.hw }, + /* + * Note: + * GXL and GXBB have different hdmi_plls (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vid_pll_div picks up the + * appropriate one. + */ + { .name = "hdmi_pll", .index = -1 }, +}; + +static struct clk_regmap gxbb_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 18 selects from 2 possible parents: + * vid_pll_div or hdmi_pll + */ + .parent_data = gxbb_vid_pll_parents, + .num_parents = ARRAY_SIZE(gxbb_vid_pll_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static const struct clk_hw *gxbb_vclk_parents[] = { + &gxbb_vid_pll.hw, + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_vid_pll.hw, + &gxbb_fclk_div7.hw, + &gxbb_mpll1.hw, +}; + +static struct clk_regmap gxbb_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 16:18 selects from 8 possible parents: + * vid_pll, fclk_div4, fclk_div3, fclk_div5, + * vid_pll, fclk_div7, mp1 + */ + .parent_hws = gxbb_vclk_parents, + .num_parents = ARRAY_SIZE(gxbb_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 16:18 selects from 8 possible parents: + * vid_pll, fclk_div4, fclk_div3, fclk_div5, + * vid_pll, fclk_div7, mp1 + */ + .parent_hws = gxbb_vclk_parents, + .num_parents = ARRAY_SIZE(gxbb_vclk_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_vclk2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_fixed_factor gxbb_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div2_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div4_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div6_en.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vclk2_div12_en.hw + }, + .num_parents = 1, + }, +}; + +static u32 gxbb_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *gxbb_cts_parents[] = { + &gxbb_vclk_div1.hw, + &gxbb_vclk_div2.hw, + &gxbb_vclk_div4.hw, + &gxbb_vclk_div6.hw, + &gxbb_vclk_div12.hw, + &gxbb_vclk2_div1.hw, + &gxbb_vclk2_div2.hw, + &gxbb_vclk2_div4.hw, + &gxbb_vclk2_div6.hw, + &gxbb_vclk2_div12.hw, +}; + +static struct clk_regmap gxbb_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = gxbb_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + .table = gxbb_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_cts_vdac_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = gxbb_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_cts_parents, + .num_parents = ARRAY_SIZE(gxbb_cts_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_enci_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_encp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap gxbb_cts_vdac = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_cts_vdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* TOFIX: add support for cts_tcon */ +static u32 gxbb_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *gxbb_hdmi_tx_parents[] = { + &gxbb_vclk_div1.hw, + &gxbb_vclk_div2.hw, + &gxbb_vclk_div4.hw, + &gxbb_vclk_div6.hw, + &gxbb_vclk_div12.hw, + &gxbb_vclk2_div1.hw, + &gxbb_vclk2_div2.hw, + &gxbb_vclk2_div4.hw, + &gxbb_vclk2_div6.hw, + &gxbb_vclk2_div12.hw, +}; + +static struct clk_regmap gxbb_hdmi_tx_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + .table = gxbb_hdmi_tx_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 31:28 selects from 12 possible parents: + * vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12 + * vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12, + * cts_tcon + */ + .parent_hws = gxbb_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(gxbb_hdmi_tx_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_hdmi_tx = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_hdmi_tx_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* HDMI Clocks */ + +static const struct clk_parent_data gxbb_hdmi_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, +}; + +static struct clk_regmap gxbb_hdmi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = gxbb_hdmi_parents, + .num_parents = ARRAY_SIZE(gxbb_hdmi_parents), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_hdmi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_hdmi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_HDMI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &gxbb_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* VDEC clocks */ + +static const struct clk_hw *gxbb_vdec_parents[] = { + &gxbb_fclk_div4.hw, + &gxbb_fclk_div3.hw, + &gxbb_fclk_div5.hw, + &gxbb_fclk_div7.hw, +}; + +static struct clk_regmap gxbb_vdec_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_vdec_parents, + .num_parents = ARRAY_SIZE(gxbb_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vdec_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vdec_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vdec_hevc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = gxbb_vdec_parents, + .num_parents = ARRAY_SIZE(gxbb_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vdec_hevc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_hevc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_vdec_hevc = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_vdec_hevc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 gxbb_gen_clk_parents_val_table[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; +static const struct clk_parent_data gxbb_gen_clk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &gxbb_vdec_1.hw }, + { .hw = &gxbb_vdec_hevc.hw }, + { .hw = &gxbb_mpll0.hw }, + { .hw = &gxbb_mpll1.hw }, + { .hw = &gxbb_mpll2.hw }, + { .hw = &gxbb_fclk_div4.hw }, + { .hw = &gxbb_fclk_div3.hw }, + { .hw = &gxbb_fclk_div5.hw }, + { .hw = &gxbb_fclk_div7.hw }, + { .hw = &gxbb_gp0_pll.hw }, +}; + +static struct clk_regmap gxbb_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_GEN_CLK_CNTL, + .mask = 0xf, + .shift = 12, + .table = gxbb_gen_clk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 15:12 selects from 14 possible parents: + * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], + * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ + .parent_data = gxbb_gen_clk_parents, + .num_parents = ARRAY_SIZE(gxbb_gen_clk_parents), + }, +}; + +static struct clk_regmap gxbb_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GEN_CLK_CNTL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_gen_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_GEN_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_gen_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data gxbb_pclk_parents = { .hw = &gxbb_clk81.hw }; + +#define GXBB_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &gxbb_pclk_parents, _flags) + +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static GXBB_PCLK(gxbb_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_spicc, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sana, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_smart_card, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sdhc, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_stream, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_async_fifo, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sdio, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_abuf, HHI_GCLK_MPEG0, 18, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hiu_iface, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_a, HHI_GCLK_MPEG0, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_b, HHI_GCLK_MPEG0, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_emmc_c, HHI_GCLK_MPEG0, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxl_acodec, HHI_GCLK_MPEG0, 28, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); + +static GXBB_PCLK(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_eth, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_blkmv, HHI_GCLK_MPEG1, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_aiu, HHI_GCLK_MPEG1, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_nand, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dos_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vdin1, HHI_GCLK_MPEG1, 28, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); + +static GXBB_PCLK(gxbb_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hdmi_intr_sync, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_hdmi_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dvin, HHI_GCLK_MPEG2, 12, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sar_adc, HHI_GCLK_MPEG2, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); + +static GXBB_PCLK(gxbb_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_venci_int0, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_vencp_int, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_gclk_venci_int1, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_venclmcc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_vclk_other, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_edp, HHI_GCLK_OTHER, 31, CLK_IGNORE_UNUSED); + +/* Always On (AO) domain gates */ + +static GXBB_PCLK(gxbb_ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); +static GXBB_PCLK(gxbb_ao_i2c, HHI_GCLK_AO, 4, CLK_IGNORE_UNUSED); + +/* AIU gates */ +static const struct clk_parent_data gxbb_aiu_glue_parents = { .hw = &gxbb_aiu.hw }; +static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu_glue_parents, CLK_IGNORE_UNUSED); + +static const struct clk_parent_data gxbb_aiu_pclk_parents = { .hw = &gxbb_aiu_glue.hw }; +#define GXBB_AIU_PCLK(_name, _bit, _flags) \ + MESON_PCLK(_name, HHI_GCLK_MPEG1, _bit, &gxbb_aiu_pclk_parents, _flags) + +static GXBB_AIU_PCLK(gxbb_iec958, 7, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_i2s_out, 8, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_amclk, 9, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_aififo2, 10, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_mixer, 11, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_mixer_iface, 12, CLK_IGNORE_UNUSED); +static GXBB_AIU_PCLK(gxbb_adc, 13, CLK_IGNORE_UNUSED); + +/* Array of all clocks provided by this provider */ + +static struct clk_hw *gxbb_hw_clks[] = { + [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, + [CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, + [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, + [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, + [CLKID_MPEG_SEL] = &gxbb_clk81_sel.hw, + [CLKID_MPEG_DIV] = &gxbb_clk81_div.hw, + [CLKID_CLK81] = &gxbb_clk81.hw, + [CLKID_MPLL0] = &gxbb_mpll0.hw, + [CLKID_MPLL1] = &gxbb_mpll1.hw, + [CLKID_MPLL2] = &gxbb_mpll2.hw, + [CLKID_DDR] = &gxbb_ddr.hw, + [CLKID_DOS] = &gxbb_dos.hw, + [CLKID_ISA] = &gxbb_isa.hw, + [CLKID_PL301] = &gxbb_pl301.hw, + [CLKID_PERIPHS] = &gxbb_periphs.hw, + [CLKID_SPICC] = &gxbb_spicc.hw, + [CLKID_I2C] = &gxbb_i2c.hw, + [CLKID_SAR_ADC] = &gxbb_sar_adc.hw, + [CLKID_SMART_CARD] = &gxbb_smart_card.hw, + [CLKID_RNG0] = &gxbb_rng0.hw, + [CLKID_UART0] = &gxbb_uart0.hw, + [CLKID_SDHC] = &gxbb_sdhc.hw, + [CLKID_STREAM] = &gxbb_stream.hw, + [CLKID_ASYNC_FIFO] = &gxbb_async_fifo.hw, + [CLKID_SDIO] = &gxbb_sdio.hw, + [CLKID_ABUF] = &gxbb_abuf.hw, + [CLKID_HIU_IFACE] = &gxbb_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &gxbb_assist_misc.hw, + [CLKID_SPI] = &gxbb_spi.hw, + [CLKID_I2S_SPDIF] = &gxbb_i2s_spdif.hw, + [CLKID_ETH] = &gxbb_eth.hw, + [CLKID_DEMUX] = &gxbb_demux.hw, + [CLKID_AIU_GLUE] = &gxbb_aiu_glue.hw, + [CLKID_IEC958] = &gxbb_iec958.hw, + [CLKID_I2S_OUT] = &gxbb_i2s_out.hw, + [CLKID_AMCLK] = &gxbb_amclk.hw, + [CLKID_AIFIFO2] = &gxbb_aififo2.hw, + [CLKID_MIXER] = &gxbb_mixer.hw, + [CLKID_MIXER_IFACE] = &gxbb_mixer_iface.hw, + [CLKID_ADC] = &gxbb_adc.hw, + [CLKID_BLKMV] = &gxbb_blkmv.hw, + [CLKID_AIU] = &gxbb_aiu.hw, + [CLKID_UART1] = &gxbb_uart1.hw, + [CLKID_G2D] = &gxbb_g2d.hw, + [CLKID_USB0] = &gxbb_usb0.hw, + [CLKID_USB1] = &gxbb_usb1.hw, + [CLKID_RESET] = &gxbb_reset.hw, + [CLKID_NAND] = &gxbb_nand.hw, + [CLKID_DOS_PARSER] = &gxbb_dos_parser.hw, + [CLKID_USB] = &gxbb_usb.hw, + [CLKID_VDIN1] = &gxbb_vdin1.hw, + [CLKID_AHB_ARB0] = &gxbb_ahb_arb0.hw, + [CLKID_EFUSE] = &gxbb_efuse.hw, + [CLKID_BOOT_ROM] = &gxbb_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &gxbb_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &gxbb_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &gxbb_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &gxbb_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &gxbb_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &gxbb_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &gxbb_mmc_pclk.hw, + [CLKID_DVIN] = &gxbb_dvin.hw, + [CLKID_UART2] = &gxbb_uart2.hw, + [CLKID_SANA] = &gxbb_sana.hw, + [CLKID_VPU_INTR] = &gxbb_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &gxbb_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A53] = &gxbb_clk81_a53.hw, + [CLKID_VCLK2_VENCI0] = &gxbb_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &gxbb_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &gxbb_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &gxbb_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT0] = &gxbb_gclk_venci_int0.hw, + [CLKID_GCLK_VENCI_INT] = &gxbb_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &gxbb_dac_clk.hw, + [CLKID_AOCLK_GATE] = &gxbb_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &gxbb_iec958_gate.hw, + [CLKID_ENC480P] = &gxbb_enc480p.hw, + [CLKID_RNG1] = &gxbb_rng1.hw, + [CLKID_GCLK_VENCI_INT1] = &gxbb_gclk_venci_int1.hw, + [CLKID_VCLK2_VENCLMCC] = &gxbb_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &gxbb_vclk2_vencl.hw, + [CLKID_VCLK_OTHER] = &gxbb_vclk_other.hw, + [CLKID_EDP] = &gxbb_edp.hw, + [CLKID_AO_MEDIA_CPU] = &gxbb_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &gxbb_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, + [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, + [CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw, + [CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw, + [CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw, + [CLKID_SAR_ADC_CLK] = &gxbb_sar_adc_clk.hw, + [CLKID_SAR_ADC_SEL] = &gxbb_sar_adc_clk_sel.hw, + [CLKID_SAR_ADC_DIV] = &gxbb_sar_adc_clk_div.hw, + [CLKID_MALI_0_SEL] = &gxbb_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &gxbb_mali_0_div.hw, + [CLKID_MALI_0] = &gxbb_mali_0.hw, + [CLKID_MALI_1_SEL] = &gxbb_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &gxbb_mali_1_div.hw, + [CLKID_MALI_1] = &gxbb_mali_1.hw, + [CLKID_MALI] = &gxbb_mali.hw, + [CLKID_CTS_AMCLK] = &gxbb_cts_amclk.hw, + [CLKID_CTS_AMCLK_SEL] = &gxbb_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &gxbb_cts_amclk_div.hw, + [CLKID_CTS_MCLK_I958] = &gxbb_cts_mclk_i958.hw, + [CLKID_CTS_MCLK_I958_SEL] = &gxbb_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &gxbb_cts_mclk_i958_div.hw, + [CLKID_CTS_I958] = &gxbb_cts_i958.hw, + [CLKID_32K_CLK] = &gxbb_32k_clk.hw, + [CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw, + [CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [CLKID_VPU_0_SEL] = &gxbb_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &gxbb_vpu_0_div.hw, + [CLKID_VPU_0] = &gxbb_vpu_0.hw, + [CLKID_VPU_1_SEL] = &gxbb_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &gxbb_vpu_1_div.hw, + [CLKID_VPU_1] = &gxbb_vpu_1.hw, + [CLKID_VPU] = &gxbb_vpu.hw, + [CLKID_VAPB_0_SEL] = &gxbb_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &gxbb_vapb_0_div.hw, + [CLKID_VAPB_0] = &gxbb_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &gxbb_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &gxbb_vapb_1_div.hw, + [CLKID_VAPB_1] = &gxbb_vapb_1.hw, + [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, + [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_HDMI_PLL_PRE_MULT] = &gxbb_hdmi_pll_pre_mult.hw, + [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, + [CLKID_VDEC_1_SEL] = &gxbb_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &gxbb_vdec_1_div.hw, + [CLKID_VDEC_1] = &gxbb_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, + [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, + [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw, + [CLKID_VID_PLL_DIV] = &gxbb_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &gxbb_vid_pll_sel.hw, + [CLKID_VID_PLL] = &gxbb_vid_pll.hw, + [CLKID_VCLK_SEL] = &gxbb_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &gxbb_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &gxbb_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &gxbb_vclk2_input.hw, + [CLKID_VCLK_DIV] = &gxbb_vclk_div.hw, + [CLKID_VCLK2_DIV] = &gxbb_vclk2_div.hw, + [CLKID_VCLK] = &gxbb_vclk.hw, + [CLKID_VCLK2] = &gxbb_vclk2.hw, + [CLKID_VCLK_DIV1] = &gxbb_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &gxbb_vclk_div2_en.hw, + [CLKID_VCLK_DIV2] = &gxbb_vclk_div2.hw, + [CLKID_VCLK_DIV4_EN] = &gxbb_vclk_div4_en.hw, + [CLKID_VCLK_DIV4] = &gxbb_vclk_div4.hw, + [CLKID_VCLK_DIV6_EN] = &gxbb_vclk_div6_en.hw, + [CLKID_VCLK_DIV6] = &gxbb_vclk_div6.hw, + [CLKID_VCLK_DIV12_EN] = &gxbb_vclk_div12_en.hw, + [CLKID_VCLK_DIV12] = &gxbb_vclk_div12.hw, + [CLKID_VCLK2_DIV1] = &gxbb_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &gxbb_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV2] = &gxbb_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_EN] = &gxbb_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV4] = &gxbb_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_EN] = &gxbb_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV6] = &gxbb_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_EN] = &gxbb_vclk2_div12_en.hw, + [CLKID_VCLK2_DIV12] = &gxbb_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &gxbb_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &gxbb_cts_encp_sel.hw, + [CLKID_CTS_VDAC_SEL] = &gxbb_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &gxbb_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &gxbb_cts_enci.hw, + [CLKID_CTS_ENCP] = &gxbb_cts_encp.hw, + [CLKID_CTS_VDAC] = &gxbb_cts_vdac.hw, + [CLKID_HDMI_TX] = &gxbb_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw, + [CLKID_HDMI] = &gxbb_hdmi.hw, +}; + +static struct clk_hw *gxl_hw_clks[] = { + [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, + [CLKID_HDMI_PLL] = &gxl_hdmi_pll.hw, + [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, + [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, + [CLKID_MPEG_SEL] = &gxbb_clk81_sel.hw, + [CLKID_MPEG_DIV] = &gxbb_clk81_div.hw, + [CLKID_CLK81] = &gxbb_clk81.hw, + [CLKID_MPLL0] = &gxbb_mpll0.hw, + [CLKID_MPLL1] = &gxbb_mpll1.hw, + [CLKID_MPLL2] = &gxbb_mpll2.hw, + [CLKID_DDR] = &gxbb_ddr.hw, + [CLKID_DOS] = &gxbb_dos.hw, + [CLKID_ISA] = &gxbb_isa.hw, + [CLKID_PL301] = &gxbb_pl301.hw, + [CLKID_PERIPHS] = &gxbb_periphs.hw, + [CLKID_SPICC] = &gxbb_spicc.hw, + [CLKID_I2C] = &gxbb_i2c.hw, + [CLKID_SAR_ADC] = &gxbb_sar_adc.hw, + [CLKID_SMART_CARD] = &gxbb_smart_card.hw, + [CLKID_RNG0] = &gxbb_rng0.hw, + [CLKID_UART0] = &gxbb_uart0.hw, + [CLKID_SDHC] = &gxbb_sdhc.hw, + [CLKID_STREAM] = &gxbb_stream.hw, + [CLKID_ASYNC_FIFO] = &gxbb_async_fifo.hw, + [CLKID_SDIO] = &gxbb_sdio.hw, + [CLKID_ABUF] = &gxbb_abuf.hw, + [CLKID_HIU_IFACE] = &gxbb_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &gxbb_assist_misc.hw, + [CLKID_SPI] = &gxbb_spi.hw, + [CLKID_I2S_SPDIF] = &gxbb_i2s_spdif.hw, + [CLKID_ETH] = &gxbb_eth.hw, + [CLKID_DEMUX] = &gxbb_demux.hw, + [CLKID_AIU_GLUE] = &gxbb_aiu_glue.hw, + [CLKID_IEC958] = &gxbb_iec958.hw, + [CLKID_I2S_OUT] = &gxbb_i2s_out.hw, + [CLKID_AMCLK] = &gxbb_amclk.hw, + [CLKID_AIFIFO2] = &gxbb_aififo2.hw, + [CLKID_MIXER] = &gxbb_mixer.hw, + [CLKID_MIXER_IFACE] = &gxbb_mixer_iface.hw, + [CLKID_ADC] = &gxbb_adc.hw, + [CLKID_BLKMV] = &gxbb_blkmv.hw, + [CLKID_AIU] = &gxbb_aiu.hw, + [CLKID_UART1] = &gxbb_uart1.hw, + [CLKID_G2D] = &gxbb_g2d.hw, + [CLKID_USB0] = &gxbb_usb0.hw, + [CLKID_USB1] = &gxbb_usb1.hw, + [CLKID_RESET] = &gxbb_reset.hw, + [CLKID_NAND] = &gxbb_nand.hw, + [CLKID_DOS_PARSER] = &gxbb_dos_parser.hw, + [CLKID_USB] = &gxbb_usb.hw, + [CLKID_VDIN1] = &gxbb_vdin1.hw, + [CLKID_AHB_ARB0] = &gxbb_ahb_arb0.hw, + [CLKID_EFUSE] = &gxbb_efuse.hw, + [CLKID_BOOT_ROM] = &gxbb_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &gxbb_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &gxbb_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &gxbb_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &gxbb_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &gxbb_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &gxbb_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &gxbb_mmc_pclk.hw, + [CLKID_DVIN] = &gxbb_dvin.hw, + [CLKID_UART2] = &gxbb_uart2.hw, + [CLKID_SANA] = &gxbb_sana.hw, + [CLKID_VPU_INTR] = &gxbb_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &gxbb_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A53] = &gxbb_clk81_a53.hw, + [CLKID_VCLK2_VENCI0] = &gxbb_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &gxbb_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &gxbb_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &gxbb_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT0] = &gxbb_gclk_venci_int0.hw, + [CLKID_GCLK_VENCI_INT] = &gxbb_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &gxbb_dac_clk.hw, + [CLKID_AOCLK_GATE] = &gxbb_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &gxbb_iec958_gate.hw, + [CLKID_ENC480P] = &gxbb_enc480p.hw, + [CLKID_RNG1] = &gxbb_rng1.hw, + [CLKID_GCLK_VENCI_INT1] = &gxbb_gclk_venci_int1.hw, + [CLKID_VCLK2_VENCLMCC] = &gxbb_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &gxbb_vclk2_vencl.hw, + [CLKID_VCLK_OTHER] = &gxbb_vclk_other.hw, + [CLKID_EDP] = &gxbb_edp.hw, + [CLKID_AO_MEDIA_CPU] = &gxbb_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &gxbb_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, + [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, + [CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw, + [CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw, + [CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw, + [CLKID_SAR_ADC_CLK] = &gxbb_sar_adc_clk.hw, + [CLKID_SAR_ADC_SEL] = &gxbb_sar_adc_clk_sel.hw, + [CLKID_SAR_ADC_DIV] = &gxbb_sar_adc_clk_div.hw, + [CLKID_MALI_0_SEL] = &gxbb_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &gxbb_mali_0_div.hw, + [CLKID_MALI_0] = &gxbb_mali_0.hw, + [CLKID_MALI_1_SEL] = &gxbb_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &gxbb_mali_1_div.hw, + [CLKID_MALI_1] = &gxbb_mali_1.hw, + [CLKID_MALI] = &gxbb_mali.hw, + [CLKID_CTS_AMCLK] = &gxbb_cts_amclk.hw, + [CLKID_CTS_AMCLK_SEL] = &gxbb_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &gxbb_cts_amclk_div.hw, + [CLKID_CTS_MCLK_I958] = &gxbb_cts_mclk_i958.hw, + [CLKID_CTS_MCLK_I958_SEL] = &gxbb_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &gxbb_cts_mclk_i958_div.hw, + [CLKID_CTS_I958] = &gxbb_cts_i958.hw, + [CLKID_32K_CLK] = &gxbb_32k_clk.hw, + [CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw, + [CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [CLKID_VPU_0_SEL] = &gxbb_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &gxbb_vpu_0_div.hw, + [CLKID_VPU_0] = &gxbb_vpu_0.hw, + [CLKID_VPU_1_SEL] = &gxbb_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &gxbb_vpu_1_div.hw, + [CLKID_VPU_1] = &gxbb_vpu_1.hw, + [CLKID_VPU] = &gxbb_vpu.hw, + [CLKID_VAPB_0_SEL] = &gxbb_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &gxbb_vapb_0_div.hw, + [CLKID_VAPB_0] = &gxbb_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &gxbb_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &gxbb_vapb_1_div.hw, + [CLKID_VAPB_1] = &gxbb_vapb_1.hw, + [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, + [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_MPLL0_DIV] = &gxl_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, + [CLKID_VDEC_1_SEL] = &gxbb_vdec_1_sel.hw, + [CLKID_VDEC_1_DIV] = &gxbb_vdec_1_div.hw, + [CLKID_VDEC_1] = &gxbb_vdec_1.hw, + [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, + [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, + [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxl_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw, + [CLKID_VID_PLL_DIV] = &gxbb_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &gxbb_vid_pll_sel.hw, + [CLKID_VID_PLL] = &gxbb_vid_pll.hw, + [CLKID_VCLK_SEL] = &gxbb_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &gxbb_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &gxbb_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &gxbb_vclk2_input.hw, + [CLKID_VCLK_DIV] = &gxbb_vclk_div.hw, + [CLKID_VCLK2_DIV] = &gxbb_vclk2_div.hw, + [CLKID_VCLK] = &gxbb_vclk.hw, + [CLKID_VCLK2] = &gxbb_vclk2.hw, + [CLKID_VCLK_DIV1] = &gxbb_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &gxbb_vclk_div2_en.hw, + [CLKID_VCLK_DIV2] = &gxbb_vclk_div2.hw, + [CLKID_VCLK_DIV4_EN] = &gxbb_vclk_div4_en.hw, + [CLKID_VCLK_DIV4] = &gxbb_vclk_div4.hw, + [CLKID_VCLK_DIV6_EN] = &gxbb_vclk_div6_en.hw, + [CLKID_VCLK_DIV6] = &gxbb_vclk_div6.hw, + [CLKID_VCLK_DIV12_EN] = &gxbb_vclk_div12_en.hw, + [CLKID_VCLK_DIV12] = &gxbb_vclk_div12.hw, + [CLKID_VCLK2_DIV1] = &gxbb_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &gxbb_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV2] = &gxbb_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_EN] = &gxbb_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV4] = &gxbb_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_EN] = &gxbb_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV6] = &gxbb_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_EN] = &gxbb_vclk2_div12_en.hw, + [CLKID_VCLK2_DIV12] = &gxbb_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &gxbb_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &gxbb_cts_encp_sel.hw, + [CLKID_CTS_VDAC_SEL] = &gxbb_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &gxbb_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &gxbb_cts_enci.hw, + [CLKID_CTS_ENCP] = &gxbb_cts_encp.hw, + [CLKID_CTS_VDAC] = &gxbb_cts_vdac.hw, + [CLKID_HDMI_TX] = &gxbb_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw, + [CLKID_HDMI] = &gxbb_hdmi.hw, + [CLKID_ACODEC] = &gxl_acodec.hw, +}; + +static const struct meson_clkc_data gxbb_clkc_data = { + .hw_clks = { + .hws = gxbb_hw_clks, + .num = ARRAY_SIZE(gxbb_hw_clks), + }, +}; + +static const struct meson_clkc_data gxl_clkc_data = { + .hw_clks = { + .hws = gxl_hw_clks, + .num = ARRAY_SIZE(gxl_hw_clks), + }, +}; + +static const struct of_device_id gxbb_clkc_match_table[] = { + { .compatible = "amlogic,gxbb-clkc", .data = &gxbb_clkc_data }, + { .compatible = "amlogic,gxl-clkc", .data = &gxl_clkc_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, gxbb_clkc_match_table); + +static struct platform_driver gxbb_clkc_driver = { + .probe = meson_clkc_syscon_probe, + .driver = { + .name = "gxbb-clkc", + .of_match_table = gxbb_clkc_match_table, + }, +}; +module_platform_driver(gxbb_clkc_driver); + +MODULE_DESCRIPTION("Amlogic GXBB Main Clock Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c new file mode 100644 index 000000000..8f6bdea18 --- /dev/null +++ b/drivers/clk/meson/meson-aoclk.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + * Author: Yixun Lan + */ + +#include +#include +#include +#include +#include + +#include +#include "meson-aoclk.h" +#include "clk-regmap.h" + +static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_aoclk_reset_controller *rstc = + container_of(rcdev, struct meson_aoclk_reset_controller, reset); + + return regmap_write(rstc->regmap, rstc->data->reset_reg, + BIT(rstc->data->reset[id])); +} + +static const struct reset_control_ops meson_aoclk_reset_ops = { + .reset = meson_aoclk_do_reset, +}; + +int meson_aoclkc_probe(struct platform_device *pdev) +{ + struct meson_aoclk_reset_controller *rstc; + const struct meson_clkc_data *clkc_data; + const struct meson_aoclk_data *data; + struct device *dev = &pdev->dev; + struct device_node *np; + struct regmap *regmap; + int ret; + + clkc_data = of_device_get_match_data(dev); + if (!clkc_data) + return -EINVAL; + + ret = meson_clkc_syscon_probe(pdev); + if (ret) + return ret; + + data = container_of(clkc_data, struct meson_aoclk_data, + clkc_data); + + rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return -ENOMEM; + + np = of_get_parent(dev->of_node); + regmap = syscon_node_to_regmap(np); + of_node_put(np); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to get regmap\n"); + return PTR_ERR(regmap); + } + + /* Reset Controller */ + rstc->data = data; + rstc->regmap = regmap; + rstc->reset.ops = &meson_aoclk_reset_ops; + rstc->reset.nr_resets = data->num_reset; + rstc->reset.of_node = dev->of_node; + ret = devm_reset_controller_register(dev, &rstc->reset); + if (ret) { + dev_err(dev, "failed to register reset controller\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(meson_aoclkc_probe, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic Always-ON Clock Controller helpers"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h new file mode 100644 index 000000000..2c83e73d3 --- /dev/null +++ b/drivers/clk/meson/meson-aoclk.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2017 BayLibre, SAS + * Author: Neil Armstrong + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + * Author: Yixun Lan + */ + +#ifndef __MESON_AOCLK_H__ +#define __MESON_AOCLK_H__ + +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "meson-clkc-utils.h" + +struct meson_aoclk_data { + const struct meson_clkc_data clkc_data; + const unsigned int reset_reg; + const int num_reset; + const unsigned int *reset; +}; + +struct meson_aoclk_reset_controller { + struct reset_controller_dev reset; + const struct meson_aoclk_data *data; + struct regmap *regmap; +}; + +int meson_aoclkc_probe(struct platform_device *pdev); +#endif diff --git a/drivers/clk/meson/meson-clkc-utils.c b/drivers/clk/meson/meson-clkc-utils.c new file mode 100644 index 000000000..870f50548 --- /dev/null +++ b/drivers/clk/meson/meson-clkc-utils.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include + +#include "meson-clkc-utils.h" + +struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_data) +{ + const struct meson_clk_hw_data *data = clk_hw_data; + unsigned int idx = clkspec->args[0]; + + if (idx >= data->num) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return data->hws[idx]; +} +EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, "CLK_MESON"); + +static int meson_clkc_init(struct device *dev, struct regmap *map) +{ + const struct meson_clkc_data *data; + struct clk_hw *hw; + int ret, i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + if (data->init_count) + regmap_multi_reg_write(map, data->init_regs, data->init_count); + + for (i = 0; i < data->hw_clks.num; i++) { + hw = data->hw_clks.hws[i]; + + /* array might be sparse */ + if (!hw) + continue; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "registering %s clock failed\n", + hw->init->name); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); +} + +int meson_clkc_syscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np; + struct regmap *map; + + np = of_get_parent(dev->of_node); + map = syscon_node_to_regmap(np); + of_node_put(np); + if (IS_ERR(map)) { + dev_err(dev, "failed to get parent syscon regmap\n"); + return PTR_ERR(map); + } + + return meson_clkc_init(dev, map); +} +EXPORT_SYMBOL_NS_GPL(meson_clkc_syscon_probe, "CLK_MESON"); + +int meson_clkc_mmio_probe(struct platform_device *pdev) +{ + const struct meson_clkc_data *data; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *base; + struct regmap *map; + struct regmap_config regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + }; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap_cfg.max_register = resource_size(res) - regmap_cfg.reg_stride; + + map = devm_regmap_init_mmio(dev, base, ®map_cfg); + if (IS_ERR(map)) + return PTR_ERR(map); + + return meson_clkc_init(dev, map); +} +EXPORT_SYMBOL_NS_GPL(meson_clkc_mmio_probe, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic Clock Controller Utilities"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-clkc-utils.h b/drivers/clk/meson/meson-clkc-utils.h new file mode 100644 index 000000000..ddadf14b4 --- /dev/null +++ b/drivers/clk/meson/meson-clkc-utils.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2023 Neil Armstrong + */ + +#ifndef __MESON_CLKC_UTILS_H__ +#define __MESON_CLKC_UTILS_H__ + +#include +#include + +struct platform_device; + +struct meson_clk_hw_data { + struct clk_hw **hws; + unsigned int num; +}; + +struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_data); + +struct meson_clkc_data { + const struct reg_sequence *init_regs; + unsigned int init_count; + struct meson_clk_hw_data hw_clks; +}; + +int meson_clkc_syscon_probe(struct platform_device *pdev); +int meson_clkc_mmio_probe(struct platform_device *pdev); + +#define __MESON_PCLK(_name, _reg, _bit, _ops, _pdata, _flags) \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = _ops, \ + .parent_data = (_pdata), \ + .num_parents = 1, \ + .flags = (_flags), \ + }, \ +} + +#define MESON_PCLK(_name, _reg, _bit, _pdata, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ops, _pdata, _flags) + +#define MESON_PCLK_RO(_name, _reg, _bit, _pdata, _flags) \ + __MESON_PCLK(_name, _reg, _bit, &clk_regmap_gate_ro_ops, _pdata, _flags) + +/* Helpers for the usual sel/div/gate composite clocks */ +#define MESON_COMP_SEL(_prefix, _name, _reg, _shift, _mask, _pdata, \ + _table, _dflags, _iflags) \ +struct clk_regmap _prefix##_name##_sel = { \ + .data = &(struct clk_regmap_mux_data) { \ + .offset = (_reg), \ + .mask = (_mask), \ + .shift = (_shift), \ + .flags = (_dflags), \ + .table = (_table), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = #_name "_sel", \ + .ops = &clk_regmap_mux_ops, \ + .parent_data = _pdata, \ + .num_parents = ARRAY_SIZE(_pdata), \ + .flags = (_iflags), \ + }, \ +} + +#define MESON_COMP_DIV(_prefix, _name, _reg, _shift, _width, \ + _dflags, _iflags) \ +struct clk_regmap _prefix##_name##_div = { \ + .data = &(struct clk_regmap_div_data) { \ + .offset = (_reg), \ + .shift = (_shift), \ + .width = (_width), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name "_div", \ + .ops = &clk_regmap_divider_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &_prefix##_name##_sel.hw \ + }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define MESON_COMP_GATE(_prefix, _name, _reg, _bit, _iflags) \ +struct clk_regmap _prefix##_name = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_hws = (const struct clk_hw *[]) { \ + &_prefix##_name##_div.hw \ + }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#endif diff --git a/drivers/clk/meson/meson8-ddr.c b/drivers/clk/meson/meson8-ddr.c new file mode 100644 index 000000000..0f93774f7 --- /dev/null +++ b/drivers/clk/meson/meson8-ddr.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson8 DDR clock controller + * + * Copyright (C) 2019 Martin Blumenstingl + */ + +#include + +#include +#include + +#include "clk-regmap.h" +#include "clk-pll.h" +#include "meson-clkc-utils.h" + +#define AM_DDR_PLL_CNTL 0x00 +#define AM_DDR_PLL_CNTL1 0x04 +#define AM_DDR_PLL_CNTL2 0x08 +#define AM_DDR_PLL_CNTL3 0x0c +#define AM_DDR_PLL_CNTL4 0x10 +#define AM_DDR_PLL_STS 0x14 +#define DDR_CLK_CNTL 0x18 +#define DDR_CLK_STS 0x1c + +static struct clk_regmap meson8_ddr_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = AM_DDR_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = AM_DDR_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = AM_DDR_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = AM_DDR_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = AM_DDR_PLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "ddr_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8_ddr_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = AM_DDR_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "ddr_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8_ddr_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_hw *meson8_ddr_hw_clks[] = { + [DDR_CLKID_DDR_PLL_DCO] = &meson8_ddr_pll_dco.hw, + [DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw, +}; + +static const struct meson_clkc_data meson8_ddr_clkc_data = { + .hw_clks = { + .hws = meson8_ddr_hw_clks, + .num = ARRAY_SIZE(meson8_ddr_hw_clks), + }, +}; + +static const struct of_device_id meson8_ddr_clkc_match_table[] = { + { + .compatible = "amlogic,meson8-ddr-clkc", + .data = &meson8_ddr_clkc_data, + }, { + .compatible = "amlogic,meson8b-ddr-clkc", + .data = &meson8_ddr_clkc_data, + }, + { /* sentinel */ } +}; + +static struct platform_driver meson8_ddr_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "meson8-ddr-clkc", + .of_match_table = meson8_ddr_clkc_match_table, + }, +}; + +builtin_platform_driver(meson8_ddr_clkc_driver); diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c new file mode 100644 index 000000000..bc029c6ab --- /dev/null +++ b/drivers/clk/meson/meson8b.c @@ -0,0 +1,3720 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + * + * Copyright (c) 2016 BayLibre, Inc. + * Michael Turquette + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-regmap.h" +#include "meson-clkc-utils.h" +#include "clk-pll.h" +#include "clk-mpll.h" + +#include +#include + +/* + * Clock controller register offsets + * + * Register offsets from the HardKernel[0] data sheet must be multiplied + * by 4 before adding them to the base address to get the right value + * + * [0] https://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf + */ +#define HHI_GP_PLL_CNTL 0x40 +#define HHI_GP_PLL_CNTL2 0x44 +#define HHI_GP_PLL_CNTL3 0x48 +#define HHI_GP_PLL_CNTL4 0x4C +#define HHI_GP_PLL_CNTL5 0x50 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12c +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_AO 0x154 +#define HHI_SYS_CPU_CLK_CNTL1 0x15c +#define HHI_VID_CLK_DIV 0x164 +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_AUD_CLK_CNTL 0x178 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_AUD_CLK_CNTL2 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_VID_DIVIDER_CNTL 0x198 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_MALI_CLK_CNTL 0x1b0 +#define HHI_VPU_CLK_CNTL 0x1bc +#define HHI_HDMI_CLK_CNTL 0x1cc +#define HHI_VDEC_CLK_CNTL 0x1e0 +#define HHI_VDEC2_CLK_CNTL 0x1e4 +#define HHI_VDEC3_CLK_CNTL 0x1e8 +#define HHI_NAND_CLK_CNTL 0x25c +#define HHI_MPLL_CNTL 0x280 +#define HHI_SYS_PLL_CNTL 0x300 +#define HHI_VID_PLL_CNTL 0x320 +#define HHI_VID_PLL_CNTL2 0x324 +#define HHI_VID_PLL_CNTL3 0x328 +#define HHI_VID_PLL_CNTL4 0x32c +#define HHI_VID_PLL_CNTL5 0x330 +#define HHI_VID_PLL_CNTL6 0x334 +#define HHI_VID2_PLL_CNTL 0x380 +#define HHI_VID2_PLL_CNTL2 0x384 +#define HHI_VID2_PLL_CNTL3 0x388 +#define HHI_VID2_PLL_CNTL4 0x38c +#define HHI_VID2_PLL_CNTL5 0x390 +#define HHI_VID2_PLL_CNTL6 0x394 + +/* + * MPLL register offeset taken from the S905 datasheet. Vendor kernel source + * confirm these are the same for the S805. + */ +#define HHI_MPLL_CNTL 0x280 +#define HHI_MPLL_CNTL2 0x284 +#define HHI_MPLL_CNTL3 0x288 +#define HHI_MPLL_CNTL4 0x28c +#define HHI_MPLL_CNTL5 0x290 +#define HHI_MPLL_CNTL6 0x294 +#define HHI_MPLL_CNTL7 0x298 +#define HHI_MPLL_CNTL8 0x29c +#define HHI_MPLL_CNTL9 0x2a0 +#define HHI_MPLL_CNTL10 0x2a4 + +struct meson8b_clk_reset { + struct reset_controller_dev reset; + struct regmap *regmap; +}; + +static const struct pll_params_table sys_pll_params_table[] = { + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(67, 1), + PLL_PARAMS(68, 1), + PLL_PARAMS(84, 1), + { /* sentinel */ }, +}; + +static struct clk_regmap meson8b_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .name = "xtal", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_fixed_factor hdmi_pll_dco_in = { + .mult = 2, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco_in", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .index = -1, + }, + .num_parents = 1, + }, +}; + +/* + * Taken from the vendor driver for the 2970/2975MHz (both only differ in the + * FRAC part in HHI_VID_PLL_CNTL2) where these values are identical for Meson8, + * Meson8b and Meson8m2. This doubles the input (or output - it's not clear + * which one but the result is the same) clock. The vendor driver additionally + * has the following comment about: "optimise HPLL VCO 2.97GHz performance". + */ +static const struct reg_sequence meson8b_hdmi_pll_init_regs[] = { + { .reg = HHI_VID_PLL_CNTL2, .def = 0x69c84000 }, + { .reg = HHI_VID_PLL_CNTL3, .def = 0x8a46c023 }, + { .reg = HHI_VID_PLL_CNTL4, .def = 0x4123b100 }, + { .reg = HHI_VID_PLL_CNTL5, .def = 0x00012385 }, + { .reg = HHI_VID2_PLL_CNTL2, .def = 0x0430a800 }, +}; + +static const struct pll_params_table meson8b_hdmi_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(68, 1), + PLL_PARAMS(71, 1), + PLL_PARAMS(82, 1), + { /* sentinel */ } +}; + +static struct clk_regmap meson8b_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_VID_PLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = meson8b_hdmi_pll_params_table, + .init_regs = meson8b_hdmi_pll_init_regs, + .init_count = ARRAY_SIZE(meson8b_hdmi_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + /* sometimes also called "HPLL" or "HPLL PLL" */ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_hws = (const struct clk_hw *[]) { + &hdmi_pll_dco_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_hdmi_pll_lvds_out = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_lvds_out", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_pll_hdmi_out = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_hdmi_out", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_sys_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = sys_pll_params_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .name = "xtal", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_sys_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div2_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div3_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mpll2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* clk81 is often referred as "mpeg_clk" */ +static u32 meson8b_clk81_parents_val_table[] = { 6, 5, 7 }; +static struct clk_regmap meson8b_clk81_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = meson8b_clk81_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_sel", + .ops = &clk_regmap_mux_ro_ops, + /* + * FIXME bits 14:12 selects from 8 possible parents: + * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, + * fclk_div4, fclk_div3, fclk_div5 + */ + .parent_hws = (const struct clk_hw *[]) { + &meson8b_fclk_div3.hw, + &meson8b_fclk_div4.hw, + &meson8b_fclk_div5.hw, + }, + .num_parents = 3, + }, +}; + +static struct clk_regmap meson8b_clk81_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_clk81_sel.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8b_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_clk81_div.hw + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap meson8b_cpu_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data[]) { + { .fw_name = "xtal", .name = "xtal", .index = -1, }, + { .hw = &meson8b_sys_pll.hw, }, + }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, +}; + +static struct clk_fixed_factor meson8b_cpu_in_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_in_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_div3", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_div_table meson8b_cpu_scale_div_table[] = { + { .val = 1, .div = 4 }, + { .val = 2, .div = 6 }, + { .val = 3, .div = 8 }, + { .val = 4, .div = 10 }, + { .val = 5, .div = 12 }, + { .val = 6, .div = 14 }, + { .val = 7, .div = 16 }, + { .val = 8, .div = 18 }, + { /* sentinel */ }, +}; + +static struct clk_regmap meson8b_cpu_scale_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 20, + .width = 10, + .table = meson8b_cpu_scale_div_table, + .flags = CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 meson8b_cpu_scale_out_parents_val_table[] = { 0, 1, 3 }; +static struct clk_regmap meson8b_cpu_scale_out_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 2, + .table = meson8b_cpu_scale_out_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_out_sel", + .ops = &clk_regmap_mux_ops, + /* + * NOTE: We are skipping the parent with value 0x2 (which is + * meson8b_cpu_in_div3) because it results in a duty cycle of + * 33% which makes the system unstable and can result in a + * lockup of the whole system. + */ + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_in_sel.hw, + &meson8b_cpu_in_div2.hw, + &meson8b_cpu_scale_div.hw, + }, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data[]) { + { .fw_name = "xtal", .name = "xtal", .index = -1, }, + { .hw = &meson8b_cpu_scale_out_sel.hw, }, + }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT | + CLK_IS_CRITICAL), + }, +}; + +static struct clk_regmap meson8b_nand_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "nand_clk_sel", + .ops = &clk_regmap_mux_ops, + /* FIXME all other parents are unknown: */ + .parent_data = (const struct clk_parent_data[]) { + { .hw = &meson8b_fclk_div4.hw, }, + { .hw = &meson8b_fclk_div3.hw, }, + { .hw = &meson8b_fclk_div5.hw, }, + { .hw = &meson8b_fclk_div7.hw, }, + { .fw_name = "xtal", .name = "xtal", .index = -1, }, + }, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_nand_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "nand_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_nand_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_nand_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "nand_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_nand_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div3", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div5 = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div5", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div7 = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div7", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_clk_div8 = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk_div8", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cpu_clk.hw + }, + .num_parents = 1, + }, +}; + +static u32 meson8b_cpu_if_parents_val_table[] = { 1, 2, 3, 4, 5, 6, 7 }; +static const struct clk_hw *meson8b_cpu_if_parents[] = { + &meson8b_cpu_clk_div2.hw, + &meson8b_cpu_clk_div3.hw, + &meson8b_cpu_clk_div4.hw, + &meson8b_cpu_clk_div5.hw, + &meson8b_cpu_clk_div6.hw, + &meson8b_cpu_clk_div7.hw, + &meson8b_cpu_clk_div8.hw, +}; + +static struct clk_regmap meson8b_apb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .mask = 0x7, + .shift = 3, + .table = meson8b_cpu_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "apb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), + }, +}; + +static struct clk_regmap meson8b_apb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 16, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data){ + .name = "apb", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_apb_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_periph_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .mask = 0x7, + .shift = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "periph_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), + }, +}; + +static struct clk_regmap meson8b_periph = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 17, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data){ + .name = "periph", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_periph_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_axi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .mask = 0x7, + .shift = 9, + .table = meson8b_cpu_if_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "axi_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), + }, +}; + +static struct clk_regmap meson8b_axi = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 18, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data){ + .name = "axi", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_axi_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_l2_dram_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .mask = 0x7, + .shift = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "l2_dram_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cpu_if_parents, + .num_parents = ARRAY_SIZE(meson8b_cpu_if_parents), + }, +}; + +static struct clk_regmap meson8b_l2_dram = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 19, + .flags = CLK_GATE_SET_TO_DISABLE, + }, + .hw.init = &(struct clk_init_data){ + .name = "l2_dram", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_l2_dram_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* also called LVDS_CLK_EN */ +static struct clk_regmap meson8b_vid_pll_lvds_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_lvds_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_lvds_out.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_in_sel", + .ops = &clk_regmap_mux_ops, + /* + * TODO: depending on the SoC there is also a second parent: + * Meson8: unknown + * Meson8b: hdmi_pll_dco + * Meson8m2: vid2_pll + */ + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_lvds_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_in_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_pre_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .shift = 4, + .width = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_pre_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_in_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_post_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .shift = 12, + .width = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_pre_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .mask = 0x3, + .shift = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &clk_regmap_mux_ops, + /* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */ + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll_pre_div.hw, + &meson8b_vid_pll_post_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_final_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_final_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vid_pll.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *meson8b_vclk_parents[] = { + &meson8b_vid_pll_final_div.hw, + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_vid_pll_final_div.hw, + &meson8b_fclk_div7.hw, + &meson8b_mpll1.hw, +}; + +static struct clk_regmap meson8b_vclk_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_parents), + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap meson8b_vclk_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_in_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div4_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div6_div = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div6 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div6_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div12_div = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div12 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk_div12_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_parents), + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_in_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div4_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div6_div = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div6 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div6_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div12_div = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div12 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vclk2_div12_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *meson8b_vclk_enc_parents[] = { + &meson8b_vclk_div1.hw, + &meson8b_vclk_div2.hw, + &meson8b_vclk_div4.hw, + &meson8b_vclk_div6.hw, + &meson8b_vclk_div12.hw, +}; + +static struct clk_regmap meson8b_cts_enct_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enct_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enct = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enct", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_enct_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_encp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_enci_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_tx_pixel = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_tx_pixel_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_vdac0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vclk_enc_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_vdac0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_vdac0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sys_sel", + .ops = &clk_regmap_mux_ops, + /* FIXME: all other parents are unknown */ + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .name = "xtal", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sys_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_sys_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_HDMI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_sys", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_sys_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can + * actually manage this glitch-free mux because it does top-to-bottom + * updates the each clock tree and switches to the "inactive" one when + * CLK_SET_RATE_GATE is set. + * Meson8 only has mali_0 and no glitch-free mux. + */ +static u32 meson8b_mali_parents_val_table[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const struct clk_parent_data meson8b_mali_parents[] = { + { .fw_name = "xtal", .name = "xtal", .index = -1, }, + { .hw = &meson8b_mpll2.hw, }, + { .hw = &meson8b_mpll1.hw, }, + { .hw = &meson8b_fclk_div7.hw, }, + { .hw = &meson8b_fclk_div4.hw, }, + { .hw = &meson8b_fclk_div3.hw, }, + { .hw = &meson8b_fclk_div5.hw, }, +}; + +static struct clk_regmap meson8b_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .table = meson8b_mali_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = meson8b_mali_parents, + .num_parents = ARRAY_SIZE(meson8b_mali_parents), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .table = meson8b_mali_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = meson8b_mali_parents, + .num_parents = ARRAY_SIZE(meson8b_mali_parents), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_mali_0.hw, + &meson8b_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence meson8m2_gp_pll_init_regs[] = { + { .reg = HHI_GP_PLL_CNTL2, .def = 0x59c88000 }, + { .reg = HHI_GP_PLL_CNTL3, .def = 0xca463823 }, + { .reg = HHI_GP_PLL_CNTL4, .def = 0x0286a027 }, + { .reg = HHI_GP_PLL_CNTL5, .def = 0x00003000 }, +}; + +static const struct pll_params_table meson8m2_gp_pll_params_table[] = { + PLL_PARAMS(182, 3), + { /* sentinel */ }, +}; + +static struct clk_regmap meson8m2_gp_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 30, + .width = 1, + }, + .m = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .l = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = meson8m2_gp_pll_params_table, + .init_regs = meson8m2_gp_pll_init_regs, + .init_count = ARRAY_SIZE(meson8m2_gp_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .name = "xtal", + .index = -1, + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap meson8m2_gp_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8m2_gp_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *meson8b_vpu_parents[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_fclk_div7.hw, +}; + +static struct clk_regmap meson8b_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vpu_parents, + .num_parents = ARRAY_SIZE(meson8b_vpu_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *mmeson8m2_vpu_parents[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8m2_gp_pll.hw, +}; + +static struct clk_regmap meson8m2_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = mmeson8m2_vpu_parents, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * meson8b and meson8m2 have different vpu_0_sels (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vpu_0_div picks up the + * appropriate one. + */ + .name = "vpu_0_sel", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vpu_parents, + .num_parents = ARRAY_SIZE(meson8b_vpu_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8m2_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = mmeson8m2_vpu_parents, + .num_parents = ARRAY_SIZE(mmeson8m2_vpu_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * meson8b and meson8m2 have different vpu_1_sels (with + * different struct clk_hw). We fallback to the global + * naming string mechanism so vpu_1_div picks up the + * appropriate one. + */ + .name = "vpu_1_sel", + .index = -1, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +/* + * The VPU clock has two identical clock trees (vpu_0 and vpu_1) + * muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can + * actually manage this glitch-free mux because it does top-to-bottom + * updates the each clock tree and switches to the "inactive" one when + * CLK_SET_RATE_GATE is set. + * Meson8 only has vpu_0 and no glitch-free mux. + */ +static struct clk_regmap meson8b_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vpu_0.hw, + &meson8b_vpu_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *meson8b_vdec_parents[] = { + &meson8b_fclk_div4.hw, + &meson8b_fclk_div3.hw, + &meson8b_fclk_div5.hw, + &meson8b_fclk_div7.hw, + &meson8b_mpll2.hw, + &meson8b_mpll1.hw, +}; + +static struct clk_regmap meson8b_vdec_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1_2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1_2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_1_2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_1 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 15, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_1", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_1_1.hw, + &meson8b_vdec_1_2.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hcodec_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hcodec_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hcodec = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hcodec", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hcodec_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_2_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_2_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_vdec_parents, + .num_parents = ARRAY_SIZE(meson8b_vdec_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_hevc_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vdec_hevc = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VDEC2_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_hevc", + .ops = &clk_regmap_mux_ops, + /* TODO: The second parent is currently unknown */ + .parent_hws = (const struct clk_hw *[]) { + &meson8b_vdec_hevc_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */ +static u32 meson8b_cts_mclk_parents_val_table[] = { 1, 2, 3 }; +static const struct clk_hw *meson8b_cts_mclk_parents[] = { + &meson8b_mpll0.hw, + &meson8b_mpll1.hw, + &meson8b_mpll2.hw +}; + +static struct clk_regmap meson8b_cts_amclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .table = meson8b_cts_mclk_parents_val_table, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cts_mclk_parents, + .num_parents = ARRAY_SIZE(meson8b_cts_mclk_parents), + }, +}; + +static struct clk_regmap meson8b_cts_amclk_div = { + .data = &(struct clk_regmap_div_data) { + .offset = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_amclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_amclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_mclk_i958_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .table = meson8b_cts_mclk_parents_val_table, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = meson8b_cts_mclk_parents, + .num_parents = ARRAY_SIZE(meson8b_cts_mclk_parents), + }, +}; + +static struct clk_regmap meson8b_cts_mclk_i958_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_mclk_i958_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_mclk_i958_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_mclk_i958 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_mclk_i958", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_mclk_i958_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_i958 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_i958", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_cts_amclk.hw, + &meson8b_cts_mclk_i958.hw + }, + .num_parents = 2, + /* + * The parent is specific to origin of the audio data. Let the + * consumer choose the appropriate parent. + */ + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + }, +}; + +static const struct clk_parent_data meson8b_pclk_parents = { .hw = &meson8b_clk81.hw }; + +#define MESON8B_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &meson8b_pclk_parents, _flags) + +/* + * Everything Else (EE) domain gates + * + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static MESON8B_PCLK(meson8b_ddr, HHI_GCLK_MPEG0, 0, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dos, HHI_GCLK_MPEG0, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_isa, HHI_GCLK_MPEG0, 5, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_pl301, HHI_GCLK_MPEG0, 6, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_periphs, HHI_GCLK_MPEG0, 7, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_spicc, HHI_GCLK_MPEG0, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_i2c, HHI_GCLK_MPEG0, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sar_adc, HHI_GCLK_MPEG0, 10, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_smart_card, HHI_GCLK_MPEG0, 11, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_rng0, HHI_GCLK_MPEG0, 12, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart0, HHI_GCLK_MPEG0, 13, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sdhc, HHI_GCLK_MPEG0, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_stream, HHI_GCLK_MPEG0, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_async_fifo, HHI_GCLK_MPEG0, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sdio, HHI_GCLK_MPEG0, 17, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_abuf, HHI_GCLK_MPEG0, 18, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hiu_iface, HHI_GCLK_MPEG0, 19, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_assist_misc, HHI_GCLK_MPEG0, 23, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_spi, HHI_GCLK_MPEG0, 30, CLK_IGNORE_UNUSED); + +static MESON8B_PCLK(meson8b_i2s_spdif, HHI_GCLK_MPEG1, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_eth, HHI_GCLK_MPEG1, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_demux, HHI_GCLK_MPEG1, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_blkmv, HHI_GCLK_MPEG1, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_aiu, HHI_GCLK_MPEG1, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart1, HHI_GCLK_MPEG1, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_g2d, HHI_GCLK_MPEG1, 20, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb0, HHI_GCLK_MPEG1, 21, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb1, HHI_GCLK_MPEG1, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_reset, HHI_GCLK_MPEG1, 23, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_nand, HHI_GCLK_MPEG1, 24, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dos_parser, HHI_GCLK_MPEG1, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb, HHI_GCLK_MPEG1, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vdin1, HHI_GCLK_MPEG1, 28, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ahb_arb0, HHI_GCLK_MPEG1, 29, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_efuse, HHI_GCLK_MPEG1, 30, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_boot_rom, HHI_GCLK_MPEG1, 31, CLK_IGNORE_UNUSED); + +static MESON8B_PCLK(meson8b_ahb_data_bus, HHI_GCLK_MPEG2, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hdmi_intr_sync, HHI_GCLK_MPEG2, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_hdmi_pclk, HHI_GCLK_MPEG2, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb1_ddr_bridge, HHI_GCLK_MPEG2, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_mmc_pclk, HHI_GCLK_MPEG2, 11, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dvin, HHI_GCLK_MPEG2, 12, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_uart2, HHI_GCLK_MPEG2, 15, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sana, HHI_GCLK_MPEG2, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vpu_intr, HHI_GCLK_MPEG2, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_clk81_a9, HHI_GCLK_MPEG2, 29, CLK_IGNORE_UNUSED); + +static MESON8B_PCLK(meson8b_vclk2_venci0, HHI_GCLK_OTHER, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_venci1, HHI_GCLK_OTHER, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencp0, HHI_GCLK_OTHER, 3, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencp1, HHI_GCLK_OTHER, 4, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_venci_int, HHI_GCLK_OTHER, 8, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_vencp_int, HHI_GCLK_OTHER, 9, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_dac_clk, HHI_GCLK_OTHER, 10, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_aoclk_gate, HHI_GCLK_OTHER, 14, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_iec958_gate, HHI_GCLK_OTHER, 16, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_enc480p, HHI_GCLK_OTHER, 20, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_rng1, HHI_GCLK_OTHER, 21, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_gclk_vencl_int, HHI_GCLK_OTHER, 22, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_venclmcc, HHI_GCLK_OTHER, 24, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_vencl, HHI_GCLK_OTHER, 25, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_vclk2_other, HHI_GCLK_OTHER, 26, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_edp, HHI_GCLK_OTHER, 31, CLK_IGNORE_UNUSED); + +/* AIU gates */ +static const struct clk_parent_data meson8b_aiu_glue_parents = { .hw = &meson8b_aiu.hw }; +static MESON_PCLK(meson8b_aiu_glue, HHI_GCLK_MPEG1, 6, + &meson8b_aiu_glue_parents, CLK_IGNORE_UNUSED); + +static const struct clk_parent_data meson8b_aiu_pclk_parents = { .hw = &meson8b_aiu_glue.hw }; +#define MESON8B_AIU_PCLK(_name, _bit, _flags) \ + MESON_PCLK(_name, HHI_GCLK_MPEG1, _bit, &meson8b_aiu_pclk_parents, _flags) + +static MESON8B_AIU_PCLK(meson8b_iec958, 7, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_i2s_out, 8, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_amclk, 9, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_aififo2, 10, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_mixer, 11, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_mixer_iface, 12, CLK_IGNORE_UNUSED); +static MESON8B_AIU_PCLK(meson8b_adc, 13, CLK_IGNORE_UNUSED); + +/* Always On (AO) domain gates */ + +static MESON8B_PCLK(meson8b_ao_media_cpu, HHI_GCLK_AO, 0, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2, CLK_IGNORE_UNUSED); +static MESON8B_PCLK(meson8b_ao_iface, HHI_GCLK_AO, 3, CLK_IGNORE_UNUSED); + +static struct clk_hw *meson8_hw_clks[] = { + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI] = &meson8b_mali_0.hw, + [CLKID_VPU_0_SEL] = &meson8b_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU] = &meson8b_vpu_0.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, + [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw, + [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw, + [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, + [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, + [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, +}; + +static struct clk_hw *meson8b_hw_clks[] = { + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI_0] = &meson8b_mali_0.hw, + [CLKID_MALI_1_SEL] = &meson8b_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, + [CLKID_MALI_1] = &meson8b_mali_1.hw, + [CLKID_MALI] = &meson8b_mali.hw, + [CLKID_VPU_0_SEL] = &meson8b_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU_0] = &meson8b_vpu_0.hw, + [CLKID_VPU_1_SEL] = &meson8b_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &meson8b_vpu_1_div.hw, + [CLKID_VPU_1] = &meson8b_vpu_1.hw, + [CLKID_VPU] = &meson8b_vpu.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_1_2_DIV] = &meson8b_vdec_1_2_div.hw, + [CLKID_VDEC_1_2] = &meson8b_vdec_1_2.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, + [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw, + [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw, + [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, + [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, + [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, +}; + +static struct clk_hw *meson8m2_hw_clks[] = { + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_clk81_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_clk81_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_APB_SEL] = &meson8b_apb_sel.hw, + [CLKID_APB] = &meson8b_apb.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_sel.hw, + [CLKID_PERIPH] = &meson8b_periph.hw, + [CLKID_AXI_SEL] = &meson8b_axi_sel.hw, + [CLKID_AXI] = &meson8b_axi.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_EN] = &meson8b_vclk_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_in_en.hw, + [CLKID_VCLK2_EN] = &meson8b_vclk2_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI_0] = &meson8b_mali_0.hw, + [CLKID_MALI_1_SEL] = &meson8b_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, + [CLKID_MALI_1] = &meson8b_mali_1.hw, + [CLKID_MALI] = &meson8b_mali.hw, + [CLKID_GP_PLL_DCO] = &meson8m2_gp_pll_dco.hw, + [CLKID_GP_PLL] = &meson8m2_gp_pll.hw, + [CLKID_VPU_0_SEL] = &meson8m2_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &meson8b_vpu_0_div.hw, + [CLKID_VPU_0] = &meson8b_vpu_0.hw, + [CLKID_VPU_1_SEL] = &meson8m2_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &meson8b_vpu_1_div.hw, + [CLKID_VPU_1] = &meson8b_vpu_1.hw, + [CLKID_VPU] = &meson8b_vpu.hw, + [CLKID_VDEC_1_SEL] = &meson8b_vdec_1_sel.hw, + [CLKID_VDEC_1_1_DIV] = &meson8b_vdec_1_1_div.hw, + [CLKID_VDEC_1_1] = &meson8b_vdec_1_1.hw, + [CLKID_VDEC_1_2_DIV] = &meson8b_vdec_1_2_div.hw, + [CLKID_VDEC_1_2] = &meson8b_vdec_1_2.hw, + [CLKID_VDEC_1] = &meson8b_vdec_1.hw, + [CLKID_VDEC_HCODEC_SEL] = &meson8b_vdec_hcodec_sel.hw, + [CLKID_VDEC_HCODEC_DIV] = &meson8b_vdec_hcodec_div.hw, + [CLKID_VDEC_HCODEC] = &meson8b_vdec_hcodec.hw, + [CLKID_VDEC_2_SEL] = &meson8b_vdec_2_sel.hw, + [CLKID_VDEC_2_DIV] = &meson8b_vdec_2_div.hw, + [CLKID_VDEC_2] = &meson8b_vdec_2.hw, + [CLKID_VDEC_HEVC_SEL] = &meson8b_vdec_hevc_sel.hw, + [CLKID_VDEC_HEVC_DIV] = &meson8b_vdec_hevc_div.hw, + [CLKID_VDEC_HEVC_EN] = &meson8b_vdec_hevc_en.hw, + [CLKID_VDEC_HEVC] = &meson8b_vdec_hevc.hw, + [CLKID_CTS_AMCLK_SEL] = &meson8b_cts_amclk_sel.hw, + [CLKID_CTS_AMCLK_DIV] = &meson8b_cts_amclk_div.hw, + [CLKID_CTS_AMCLK] = &meson8b_cts_amclk.hw, + [CLKID_CTS_MCLK_I958_SEL] = &meson8b_cts_mclk_i958_sel.hw, + [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, + [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, + [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, +}; + +static const struct meson8b_clk_reset_line { + u32 reg; + u8 bit_idx; + bool active_low; +} meson8b_clk_reset_bits[] = { + [CLKC_RESET_L2_CACHE_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 30, + .active_low = false, + }, + [CLKC_RESET_AXI_64_TO_128_BRIDGE_A5_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 29, + .active_low = false, + }, + [CLKC_RESET_SCU_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 28, + .active_low = false, + }, + [CLKC_RESET_CPU3_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 27, + .active_low = false, + }, + [CLKC_RESET_CPU2_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 26, + .active_low = false, + }, + [CLKC_RESET_CPU1_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 25, + .active_low = false, + }, + [CLKC_RESET_CPU0_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 24, + .active_low = false, + }, + [CLKC_RESET_A5_GLOBAL_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 18, + .active_low = false, + }, + [CLKC_RESET_A5_AXI_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 17, + .active_low = false, + }, + [CLKC_RESET_A5_ABP_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL0, + .bit_idx = 16, + .active_low = false, + }, + [CLKC_RESET_AXI_64_TO_128_BRIDGE_MMC_SOFT_RESET] = { + .reg = HHI_SYS_CPU_CLK_CNTL1, + .bit_idx = 30, + .active_low = false, + }, + [CLKC_RESET_VID_CLK_CNTL_SOFT_RESET] = { + .reg = HHI_VID_CLK_CNTL, + .bit_idx = 15, + .active_low = false, + }, + [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST] = { + .reg = HHI_VID_DIVIDER_CNTL, + .bit_idx = 7, + .active_low = false, + }, + [CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE] = { + .reg = HHI_VID_DIVIDER_CNTL, + .bit_idx = 3, + .active_low = false, + }, + [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST] = { + .reg = HHI_VID_DIVIDER_CNTL, + .bit_idx = 1, + .active_low = true, + }, + [CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE] = { + .reg = HHI_VID_DIVIDER_CNTL, + .bit_idx = 0, + .active_low = true, + }, +}; + +static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct meson8b_clk_reset *meson8b_clk_reset = + container_of(rcdev, struct meson8b_clk_reset, reset); + const struct meson8b_clk_reset_line *reset; + unsigned int value = 0; + + if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) + return -EINVAL; + + reset = &meson8b_clk_reset_bits[id]; + + if (assert != reset->active_low) + value = BIT(reset->bit_idx); + + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), value); + + return 0; +} + +static int meson8b_clk_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson8b_clk_reset_update(rcdev, id, true); +} + +static int meson8b_clk_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson8b_clk_reset_update(rcdev, id, false); +} + +static const struct reset_control_ops meson8b_clk_reset_ops = { + .assert = meson8b_clk_reset_assert, + .deassert = meson8b_clk_reset_deassert, +}; + +struct meson8b_nb_data { + struct notifier_block nb; + struct clk_hw *cpu_clk; +}; + +static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct meson8b_nb_data *nb_data = + container_of(nb, struct meson8b_nb_data, nb); + struct clk_hw *parent_clk; + int ret; + + switch (event) { + case PRE_RATE_CHANGE: + /* xtal */ + parent_clk = clk_hw_get_parent_by_index(nb_data->cpu_clk, 0); + break; + + case POST_RATE_CHANGE: + /* cpu_scale_out_sel */ + parent_clk = clk_hw_get_parent_by_index(nb_data->cpu_clk, 1); + break; + + default: + return NOTIFY_DONE; + } + + ret = clk_hw_set_parent(nb_data->cpu_clk, parent_clk); + if (ret) + return notifier_from_errno(ret); + + udelay(100); + + return NOTIFY_OK; +} + +static struct meson8b_nb_data meson8b_cpu_nb_data = { + .nb.notifier_call = meson8b_cpu_clk_notifier_cb, +}; + +static struct meson_clk_hw_data meson8_clks = { + .hws = meson8_hw_clks, + .num = ARRAY_SIZE(meson8_hw_clks), +}; + +static struct meson_clk_hw_data meson8b_clks = { + .hws = meson8b_hw_clks, + .num = ARRAY_SIZE(meson8b_hw_clks), +}; + +static struct meson_clk_hw_data meson8m2_clks = { + .hws = meson8m2_hw_clks, + .num = ARRAY_SIZE(meson8m2_hw_clks), +}; + +static void __init meson8b_clkc_init_common(struct device_node *np, + struct meson_clk_hw_data *hw_clks) +{ + struct meson8b_clk_reset *rstc; + struct device_node *parent_np; + const char *notifier_clk_name; + struct clk *notifier_clk; + struct regmap *map; + int i, ret; + + parent_np = of_get_parent(np); + map = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); + if (IS_ERR(map)) { + pr_err("failed to get HHI regmap - Trying obsolete regs\n"); + return; + } + + rstc = kzalloc_obj(*rstc); + if (!rstc) + return; + + /* Reset Controller */ + rstc->regmap = map; + rstc->reset.ops = &meson8b_clk_reset_ops; + rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits); + rstc->reset.of_node = np; + ret = reset_controller_register(&rstc->reset); + if (ret) { + pr_err("%s: Failed to register clkc reset controller: %d\n", + __func__, ret); + return; + } + + /* + * register all clks and start with the first used ID (which is + * CLKID_PLL_FIXED) + */ + for (i = CLKID_PLL_FIXED; i < hw_clks->num; i++) { + /* array might be sparse */ + if (!hw_clks->hws[i]) + continue; + + ret = of_clk_hw_register(np, hw_clks->hws[i]); + if (ret) + return; + } + + meson8b_cpu_nb_data.cpu_clk = hw_clks->hws[CLKID_CPUCLK]; + + /* + * FIXME we shouldn't program the muxes in notifier handlers. The + * tricky programming sequence will be handled by the forthcoming + * coordinated clock rates mechanism once that feature is released. + */ + notifier_clk_name = clk_hw_get_name(&meson8b_cpu_scale_out_sel.hw); + notifier_clk = __clk_lookup(notifier_clk_name); + ret = clk_notifier_register(notifier_clk, &meson8b_cpu_nb_data.nb); + if (ret) { + pr_err("%s: failed to register the CPU clock notifier\n", + __func__); + return; + } + + ret = of_clk_add_hw_provider(np, meson_clk_hw_get, hw_clks); + if (ret) + pr_err("%s: failed to register clock provider\n", __func__); +} + +static void __init meson8_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8_clks); +} + +static void __init meson8b_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8b_clks); +} + +static void __init meson8m2_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8m2_clks); +} + +CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", + meson8_clkc_init); +CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", + meson8b_clkc_init); +CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", + meson8m2_clkc_init); diff --git a/drivers/clk/meson/parm.h b/drivers/clk/meson/parm.h new file mode 100644 index 000000000..3c9ef1b50 --- /dev/null +++ b/drivers/clk/meson/parm.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + */ + +#ifndef __MESON_PARM_H +#define __MESON_PARM_H + +#include +#include + +#define PMASK(width) GENMASK(width - 1, 0) +#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) +#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) + +#define PARM_GET(width, shift, reg) \ + (((reg) & SETPMASK(width, shift)) >> (shift)) +#define PARM_SET(width, shift, reg, val) \ + (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) + +#define MESON_PARM_APPLICABLE(p) (!!((p)->width)) + +struct parm { + u16 reg_off; + u8 shift; + u8 width; +}; + +static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p) +{ + unsigned int val; + + regmap_read(map, p->reg_off, &val); + return PARM_GET(p->width, p->shift, val); +} + +static inline void meson_parm_write(struct regmap *map, struct parm *p, + unsigned int val) +{ + regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift), + val << p->shift); +} + +#endif /* __MESON_PARM_H */ + diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c new file mode 100644 index 000000000..ba41fcd90 --- /dev/null +++ b/drivers/clk/meson/s4-peripherals.c @@ -0,0 +1,3259 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Amlogic S4 Peripherals Clock Controller Driver + * + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-regmap.h" +#include "vid-pll-div.h" +#include "clk-dualdiv.h" +#include "meson-clkc-utils.h" +#include + +#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x008 +#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0x00c +#define CLKCTRL_RTC_CTRL 0x010 +#define CLKCTRL_SYS_CLK_CTRL0 0x040 +#define CLKCTRL_SYS_CLK_EN0_REG0 0x044 +#define CLKCTRL_SYS_CLK_EN0_REG1 0x048 +#define CLKCTRL_SYS_CLK_EN0_REG2 0x04c +#define CLKCTRL_SYS_CLK_EN0_REG3 0x050 +#define CLKCTRL_CECA_CTRL0 0x088 +#define CLKCTRL_CECA_CTRL1 0x08c +#define CLKCTRL_CECB_CTRL0 0x090 +#define CLKCTRL_CECB_CTRL1 0x094 +#define CLKCTRL_SC_CLK_CTRL 0x098 +#define CLKCTRL_CLK12_24_CTRL 0x0a8 +#define CLKCTRL_VID_CLK_CTRL 0x0c0 +#define CLKCTRL_VID_CLK_CTRL2 0x0c4 +#define CLKCTRL_VID_CLK_DIV 0x0c8 +#define CLKCTRL_VIID_CLK_DIV 0x0cc +#define CLKCTRL_VIID_CLK_CTRL 0x0d0 +#define CLKCTRL_HDMI_CLK_CTRL 0x0e0 +#define CLKCTRL_VID_PLL_CLK_DIV 0x0e4 +#define CLKCTRL_VPU_CLK_CTRL 0x0e8 +#define CLKCTRL_VPU_CLKB_CTRL 0x0ec +#define CLKCTRL_VPU_CLKC_CTRL 0x0f0 +#define CLKCTRL_VID_LOCK_CLK_CTRL 0x0f4 +#define CLKCTRL_VDIN_MEAS_CLK_CTRL 0x0f8 +#define CLKCTRL_VAPBCLK_CTRL 0x0fc +#define CLKCTRL_HDCP22_CTRL 0x100 +#define CLKCTRL_CDAC_CLK_CTRL 0x108 +#define CLKCTRL_VDEC_CLK_CTRL 0x140 +#define CLKCTRL_VDEC2_CLK_CTRL 0x144 +#define CLKCTRL_VDEC3_CLK_CTRL 0x148 +#define CLKCTRL_VDEC4_CLK_CTRL 0x14c +#define CLKCTRL_TS_CLK_CTRL 0x158 +#define CLKCTRL_MALI_CLK_CTRL 0x15c +#define CLKCTRL_NAND_CLK_CTRL 0x168 +#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c +#define CLKCTRL_SPICC_CLK_CTRL 0x174 +#define CLKCTRL_GEN_CLK_CTRL 0x178 +#define CLKCTRL_SAR_CLK_CTRL 0x17c +#define CLKCTRL_PWM_CLK_AB_CTRL 0x180 +#define CLKCTRL_PWM_CLK_CD_CTRL 0x184 +#define CLKCTRL_PWM_CLK_EF_CTRL 0x188 +#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c +#define CLKCTRL_PWM_CLK_IJ_CTRL 0x190 +#define CLKCTRL_DEMOD_CLK_CTRL 0x200 + +#define S4_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(s4_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define S4_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(s4_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define S4_COMP_GATE(_name, _reg, _bit) \ + MESON_COMP_GATE(s4_, _name, _reg, _bit, CLK_SET_RATE_PARENT) + +static struct clk_regmap s4_rtc_32k_by_oscin_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_by_oscin_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param s4_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, + {} +}; + +static struct clk_regmap s4_rtc_32k_by_oscin_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_by_oscin_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_rtc_32k_by_oscin_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_by_oscin_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_div.hw, + &s4_rtc_32k_by_oscin_clkin.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_rtc_32k_by_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_by_oscin", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_rtc_clk = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_RTC_CTRL, + .mask = 0x3, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin.hw, + &s4_rtc_32k_by_oscin_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* The index 5 is AXI_CLK, which is dedicated to AXI. So skip it. */ +static u32 s4_sysclk_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 }; +static const struct clk_parent_data s4_sysclk_parents[] = { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div2" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "fclk_div7" }, + { .hw = &s4_rtc_clk.hw } +}; + +/* + * This clock is initialized by ROMcode. + * The chip was changed SYS CLK for security reasons. SYS CLK registers are not writable + * in the kernel phase. Write of SYS related register will cause the system to crash. + * Meanwhile, these clock won't ever change at runtime. + * For the above reasons, we can only use ro_ops for SYS related clocks. + */ +static struct clk_regmap s4_sysclk_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 26, + .table = s4_sysclk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_b_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = s4_sysclk_parents, + .num_parents = ARRAY_SIZE(s4_sysclk_parents), + }, +}; + +static struct clk_regmap s4_sysclk_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .shift = 16, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_b_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_b_sel.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data) { + .name = "sysclk_b", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_b_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 10, + .table = s4_sysclk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_a_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = s4_sysclk_parents, + .num_parents = ARRAY_SIZE(s4_sysclk_parents), + }, +}; + +static struct clk_regmap s4_sysclk_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .shift = 0, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_a_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a_sel.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "sysclk_a", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sys_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a.hw, + &s4_sysclk_b.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_ceca_32k_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECA_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ceca_32k_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_ceca_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_CECA_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_CECA_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_ceca_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECA_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_div.hw, + &s4_ceca_32k_clkin.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ceca_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECA_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_sel_pre.hw, + &s4_rtc_clk.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_ceca_32k_clkout = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECA_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_clkout", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cecb_32k_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECB_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "cecb_32k_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_cecb_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_CECB_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_CECB_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_cecb_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECB_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_div.hw, + &s4_cecb_32k_clkin.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cecb_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECB_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_sel_pre.hw, + &s4_rtc_clk.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_cecb_32k_clkout = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECB_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_clkout", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_sc_clk_parents[] = { + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "xtal", } +}; + +static struct clk_regmap s4_sc_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sc_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sc_clk_parents, + .num_parents = ARRAY_SIZE(s4_sc_clk_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "sc_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sc_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sc_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "sc_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sc_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_12_24M = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "12_24M", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_12M_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "12M_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_12_24M.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_12_24M_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_CLK12_24_CTRL, + .mask = 0x1, + .shift = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "12_24M_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_12_24M.hw, + &s4_12M_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Video Clocks */ +static struct clk_regmap s4_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = CLKCTRL_VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = CLKCTRL_VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + /* + * TODO meson_vid_pll_div_ro_ops to meson_vid_pll_div_ops + */ + .ops = &meson_vid_pll_div_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "hdmi_pll", } + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &s4_vid_pll_div.hw }, + { .fw_name = "hdmi_pll", } + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vclk_parents[] = { + { .hw = &s4_vid_pll.hw }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "mpll1", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, +}; + +static struct clk_regmap s4_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vclk_parents, + .num_parents = ARRAY_SIZE(s4_vclk_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vclk_parents, + .num_parents = ARRAY_SIZE(s4_vclk_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div4_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div6_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div12_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div4_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div6_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div12_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ +static u32 s4_cts_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_cts_parents[] = { + &s4_vclk_div1.hw, + &s4_vclk_div2.hw, + &s4_vclk_div4.hw, + &s4_vclk_div6.hw, + &s4_vclk_div12.hw, + &s4_vclk2_div1.hw, + &s4_vclk2_div2.hw, + &s4_vclk2_div4.hw, + &s4_vclk2_div6.hw, + &s4_vclk2_div12.hw +}; + +static struct clk_regmap s4_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = s4_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), + }, +}; + +static struct clk_regmap s4_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + .table = s4_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), + }, +}; + +static struct clk_regmap s4_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = s4_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), + }, +}; + +static struct clk_regmap s4_cts_vdac_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = s4_cts_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parents, + .num_parents = ARRAY_SIZE(s4_cts_parents), + }, +}; + +/* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ +static u32 s4_hdmi_tx_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_hdmi_tx_parents[] = { + &s4_vclk_div1.hw, + &s4_vclk_div2.hw, + &s4_vclk_div4.hw, + &s4_vclk_div6.hw, + &s4_vclk_div12.hw, + &s4_vclk2_div1.hw, + &s4_vclk2_div2.hw, + &s4_vclk2_div4.hw, + &s4_vclk2_div6.hw, + &s4_vclk2_div12.hw +}; + +static struct clk_regmap s4_hdmi_tx_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 16, + .table = s4_hdmi_tx_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_hdmi_tx_parents, + .num_parents = ARRAY_SIZE(s4_hdmi_tx_parents), + }, +}; + +static struct clk_regmap s4_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_enci_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_encp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_vdac = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_vdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_tx = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_tx_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* HDMI Clocks */ +static const struct clk_parent_data s4_hdmi_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", } +}; + +static struct clk_regmap s4_hdmi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_hdmi_parents, + .num_parents = ARRAY_SIZE(s4_hdmi_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ts_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ts_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ts_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. The CCF can manage this glitch-free + * mux because it does top-to-bottom updates the each clock tree and + * switches to the "inactive" one when CLK_SET_RATE_GATE is set. + */ +static const struct clk_parent_data s4_mali_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2p5", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", } +}; + +static struct clk_regmap s4_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_mali_parents, + .num_parents = ARRAY_SIZE(s4_mali_parents), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the HIFI PLL clock for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap s4_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_mali_parents, + .num_parents = ARRAY_SIZE(s4_mali_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0.hw, + &s4_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VDEC clocks */ +static const struct clk_parent_data s4_dec_parents[] = { + { .fw_name = "fclk_div2p5", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "gp0_pll", }, + { .fw_name = "xtal", } +}; + +static struct clk_regmap s4_vdec_p0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vdec_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vdec_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0.hw, + &s4_vdec_p1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_hevcf_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parents, + .num_parents = ARRAY_SIZE(s4_dec_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_hevcf_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0.hw, + &s4_hevcf_p1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VPU Clock */ +static const struct clk_parent_data s4_vpu_parents[] = { + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "hifi_pll", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_parents, + .num_parents = ARRAY_SIZE(s4_vpu_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_parents, + .num_parents = ARRAY_SIZE(s4_vpu_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_0.hw, + &s4_vpu_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data vpu_clkb_tmp_parents[] = { + { .hw = &s4_vpu.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", } +}; + +static struct clk_regmap s4_vpu_clkb_tmp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .mask = 0x3, + .shift = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_tmp_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = vpu_clkb_tmp_parents, + .num_parents = ARRAY_SIZE(vpu_clkb_tmp_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_tmp_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .shift = 16, + .width = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_tmp_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_tmp = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkb_tmp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vpu_clkc_parents[] = { + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "mpll2", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_vpu_clkc_p0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_clkc_parents, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkc_p0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_clkc_parents, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkc_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0.hw, + &s4_vpu_clkc_p1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VAPB Clock */ +static const struct clk_parent_data s4_vapb_parents[] = { + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "mpll2", }, + { .fw_name = "fclk_div2p5", }, +}; + +static struct clk_regmap s4_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vapb_parents, + .num_parents = ARRAY_SIZE(s4_vapb_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vapb_parents, + .num_parents = ARRAY_SIZE(s4_vapb_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0.hw, + &s4_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ge2d = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "ge2d", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vapb.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_hdcp22_esmclk_parents[] = { + { .fw_name = "fclk_div7", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, +}; + +static struct clk_regmap s4_hdcp22_esmclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_esmclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_hdcp22_esmclk_parents, + .num_parents = ARRAY_SIZE(s4_hdcp22_esmclk_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_esmclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_esmclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_esmclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_esmclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdcp22_esmclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_esmclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_hdcp22_skpclk_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, +}; + +static struct clk_regmap s4_hdcp22_skpclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_skpclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_hdcp22_skpclk_parents, + .num_parents = ARRAY_SIZE(s4_hdcp22_skpclk_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_skpclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_skpclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_skpclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_skpclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdcp22_skpclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_skpclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vdin_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .hw = &s4_vid_pll.hw } +}; + +static struct clk_regmap s4_vdin_meas_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vdin_parents, + .num_parents = ARRAY_SIZE(s4_vdin_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdin_meas_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdin_meas_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdin_meas = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdin_meas_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static const struct clk_parent_data s4_sd_emmc_clk0_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2p5", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_c_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_c_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_a_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_a_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parents, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parents), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_b_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_b_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* SPICC Clock */ +static const struct clk_parent_data s4_spicc_parents[] = { + { .fw_name = "xtal", }, + { .hw = &s4_sys_clk.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, +}; + +static struct clk_regmap s4_spicc0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .mask = 0x7, + .shift = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "spicc0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_spicc_parents, + .num_parents = ARRAY_SIZE(s4_spicc_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_spicc0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .shift = 0, + .width = 6, + }, + .hw.init = &(struct clk_init_data) { + .name = "spicc0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_spicc0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_spicc0_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_spicc0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* PWM Clock */ +static const struct clk_parent_data s4_pwm_parents[] = { + { .fw_name = "xtal", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, +}; + +static S4_COMP_SEL(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 0, 8); +static S4_COMP_GATE(pwm_a, CLKCTRL_PWM_CLK_AB_CTRL, 8); + +static S4_COMP_SEL(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 16, 8); +static S4_COMP_GATE(pwm_b, CLKCTRL_PWM_CLK_AB_CTRL, 24); + +static S4_COMP_SEL(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 0, 8); +static S4_COMP_GATE(pwm_c, CLKCTRL_PWM_CLK_CD_CTRL, 8); + +static S4_COMP_SEL(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 16, 8); +static S4_COMP_GATE(pwm_d, CLKCTRL_PWM_CLK_CD_CTRL, 24); + +static S4_COMP_SEL(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 0, 8); +static S4_COMP_GATE(pwm_e, CLKCTRL_PWM_CLK_EF_CTRL, 8); + +static S4_COMP_SEL(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 16, 8); +static S4_COMP_GATE(pwm_f, CLKCTRL_PWM_CLK_EF_CTRL, 24); + +static S4_COMP_SEL(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 0, 8); +static S4_COMP_GATE(pwm_g, CLKCTRL_PWM_CLK_GH_CTRL, 8); + +static S4_COMP_SEL(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 16, 8); +static S4_COMP_GATE(pwm_h, CLKCTRL_PWM_CLK_GH_CTRL, 24); + +static S4_COMP_SEL(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 9, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 0, 8); +static S4_COMP_GATE(pwm_i, CLKCTRL_PWM_CLK_IJ_CTRL, 8); + +static S4_COMP_SEL(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 25, 0x3, s4_pwm_parents); +static S4_COMP_DIV(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 16, 8); +static S4_COMP_GATE(pwm_j, CLKCTRL_PWM_CLK_IJ_CTRL, 24); + +static struct clk_regmap s4_saradc_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &s4_sys_clk.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_saradc_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_saradc_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_saradc = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_saradc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * gen clk is designed for debug/monitor some internal clock quality. Some of the + * corresponding clock sources are not described in the clock tree and internal clock + * for debug, so they are skipped. + */ +static u32 s4_gen_clk_parents_val_table[] = { 0, 4, 5, 7, 19, 21, 22, 23, 24, 25, 26, 27, 28 }; +static const struct clk_parent_data s4_gen_clk_parents[] = { + { .fw_name = "xtal", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll0", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, +}; + +static struct clk_regmap s4_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .mask = 0x1f, + .shift = 12, + .table = s4_gen_clk_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_gen_clk_parents, + .num_parents = ARRAY_SIZE(s4_gen_clk_parents), + /* + * Because the GEN clock can be connected to an external pad + * and may be set up directly from the device tree. Don't + * really want to automatically reparent. + */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap s4_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gen_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gen_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* CVBS DAC */ +static struct clk_regmap s4_cdac_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div5" }, + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_cdac_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .shift = 0, + .width = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cdac = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_CDAC_CLK_CTRL, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "cdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cdac_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div7" }, + { .fw_name = "fclk_div4" } + }, + .num_parents = 3, + }, +}; + +static struct clk_regmap s4_demod_core_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 8 + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* CVBS ADC */ +static struct clk_regmap s4_adc_extclk_in_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "fclk_div7" }, + { .fw_name = "mpll2" }, + { .fw_name = "gp0_pll" }, + { .fw_name = "hifi_pll" } + }, + .num_parents = 8, + }, +}; + +static struct clk_regmap s4_adc_extclk_in_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_adc_extclk_in = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 24 + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_pclk_parents = { .hw = &s4_sys_clk.hw }; + +#define S4_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(_name, _reg, _bit, &s4_pclk_parents, _flags) + +/* + * NOTE: The gates below are marked with CLK_IGNORE_UNUSED for historic reasons + * Users are encouraged to test without it and submit changes to: + * - remove the flag if not necessary + * - replace the flag with something more adequate, such as CLK_IS_CRITICAL, + * if appropriate. + * - add a comment explaining why the use of CLK_IGNORE_UNUSED is desirable + * for a particular clock. + */ +static S4_PCLK(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31, CLK_IGNORE_UNUSED); + +static S4_PCLK(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31, CLK_IGNORE_UNUSED); + +static S4_PCLK(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30, CLK_IGNORE_UNUSED); + +static S4_PCLK(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10, CLK_IGNORE_UNUSED); +static S4_PCLK(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11, CLK_IGNORE_UNUSED); + +/* Array of all clocks provided by this provider */ +static struct clk_hw *s4_peripherals_hw_clks[] = { + [CLKID_RTC_32K_CLKIN] = &s4_rtc_32k_by_oscin_clkin.hw, + [CLKID_RTC_32K_DIV] = &s4_rtc_32k_by_oscin_div.hw, + [CLKID_RTC_32K_SEL] = &s4_rtc_32k_by_oscin_sel.hw, + [CLKID_RTC_32K_XATL] = &s4_rtc_32k_by_oscin.hw, + [CLKID_RTC] = &s4_rtc_clk.hw, + [CLKID_SYS_CLK_B_SEL] = &s4_sysclk_b_sel.hw, + [CLKID_SYS_CLK_B_DIV] = &s4_sysclk_b_div.hw, + [CLKID_SYS_CLK_B] = &s4_sysclk_b.hw, + [CLKID_SYS_CLK_A_SEL] = &s4_sysclk_a_sel.hw, + [CLKID_SYS_CLK_A_DIV] = &s4_sysclk_a_div.hw, + [CLKID_SYS_CLK_A] = &s4_sysclk_a.hw, + [CLKID_SYS] = &s4_sys_clk.hw, + [CLKID_CECA_32K_CLKIN] = &s4_ceca_32k_clkin.hw, + [CLKID_CECA_32K_DIV] = &s4_ceca_32k_div.hw, + [CLKID_CECA_32K_SEL_PRE] = &s4_ceca_32k_sel_pre.hw, + [CLKID_CECA_32K_SEL] = &s4_ceca_32k_sel.hw, + [CLKID_CECA_32K_CLKOUT] = &s4_ceca_32k_clkout.hw, + [CLKID_CECB_32K_CLKIN] = &s4_cecb_32k_clkin.hw, + [CLKID_CECB_32K_DIV] = &s4_cecb_32k_div.hw, + [CLKID_CECB_32K_SEL_PRE] = &s4_cecb_32k_sel_pre.hw, + [CLKID_CECB_32K_SEL] = &s4_cecb_32k_sel.hw, + [CLKID_CECB_32K_CLKOUT] = &s4_cecb_32k_clkout.hw, + [CLKID_SC_CLK_SEL] = &s4_sc_clk_sel.hw, + [CLKID_SC_CLK_DIV] = &s4_sc_clk_div.hw, + [CLKID_SC] = &s4_sc_clk.hw, + [CLKID_12_24M] = &s4_12_24M.hw, + [CLKID_12M_CLK_DIV] = &s4_12M_div.hw, + [CLKID_12_24M_CLK_SEL] = &s4_12_24M_sel.hw, + [CLKID_VID_PLL_DIV] = &s4_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &s4_vid_pll_sel.hw, + [CLKID_VID_PLL] = &s4_vid_pll.hw, + [CLKID_VCLK_SEL] = &s4_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &s4_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &s4_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &s4_vclk2_input.hw, + [CLKID_VCLK_DIV] = &s4_vclk_div.hw, + [CLKID_VCLK2_DIV] = &s4_vclk2_div.hw, + [CLKID_VCLK] = &s4_vclk.hw, + [CLKID_VCLK2] = &s4_vclk2.hw, + [CLKID_VCLK_DIV1] = &s4_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &s4_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &s4_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &s4_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &s4_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &s4_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &s4_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &s4_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &s4_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &s4_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &s4_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &s4_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &s4_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &s4_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &s4_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &s4_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &s4_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &s4_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &s4_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &s4_cts_encp_sel.hw, + [CLKID_CTS_VDAC_SEL] = &s4_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &s4_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &s4_cts_enci.hw, + [CLKID_CTS_ENCP] = &s4_cts_encp.hw, + [CLKID_CTS_VDAC] = &s4_cts_vdac.hw, + [CLKID_HDMI_TX] = &s4_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &s4_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &s4_hdmi_div.hw, + [CLKID_HDMI] = &s4_hdmi.hw, + [CLKID_TS_CLK_DIV] = &s4_ts_clk_div.hw, + [CLKID_TS] = &s4_ts_clk.hw, + [CLKID_MALI_0_SEL] = &s4_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &s4_mali_0_div.hw, + [CLKID_MALI_0] = &s4_mali_0.hw, + [CLKID_MALI_1_SEL] = &s4_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &s4_mali_1_div.hw, + [CLKID_MALI_1] = &s4_mali_1.hw, + [CLKID_MALI_SEL] = &s4_mali_sel.hw, + [CLKID_VDEC_P0_SEL] = &s4_vdec_p0_sel.hw, + [CLKID_VDEC_P0_DIV] = &s4_vdec_p0_div.hw, + [CLKID_VDEC_P0] = &s4_vdec_p0.hw, + [CLKID_VDEC_P1_SEL] = &s4_vdec_p1_sel.hw, + [CLKID_VDEC_P1_DIV] = &s4_vdec_p1_div.hw, + [CLKID_VDEC_P1] = &s4_vdec_p1.hw, + [CLKID_VDEC_SEL] = &s4_vdec_sel.hw, + [CLKID_HEVCF_P0_SEL] = &s4_hevcf_p0_sel.hw, + [CLKID_HEVCF_P0_DIV] = &s4_hevcf_p0_div.hw, + [CLKID_HEVCF_P0] = &s4_hevcf_p0.hw, + [CLKID_HEVCF_P1_SEL] = &s4_hevcf_p1_sel.hw, + [CLKID_HEVCF_P1_DIV] = &s4_hevcf_p1_div.hw, + [CLKID_HEVCF_P1] = &s4_hevcf_p1.hw, + [CLKID_HEVCF_SEL] = &s4_hevcf_sel.hw, + [CLKID_VPU_0_SEL] = &s4_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &s4_vpu_0_div.hw, + [CLKID_VPU_0] = &s4_vpu_0.hw, + [CLKID_VPU_1_SEL] = &s4_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &s4_vpu_1_div.hw, + [CLKID_VPU_1] = &s4_vpu_1.hw, + [CLKID_VPU] = &s4_vpu.hw, + [CLKID_VPU_CLKB_TMP_SEL] = &s4_vpu_clkb_tmp_sel.hw, + [CLKID_VPU_CLKB_TMP_DIV] = &s4_vpu_clkb_tmp_div.hw, + [CLKID_VPU_CLKB_TMP] = &s4_vpu_clkb_tmp.hw, + [CLKID_VPU_CLKB_DIV] = &s4_vpu_clkb_div.hw, + [CLKID_VPU_CLKB] = &s4_vpu_clkb.hw, + [CLKID_VPU_CLKC_P0_SEL] = &s4_vpu_clkc_p0_sel.hw, + [CLKID_VPU_CLKC_P0_DIV] = &s4_vpu_clkc_p0_div.hw, + [CLKID_VPU_CLKC_P0] = &s4_vpu_clkc_p0.hw, + [CLKID_VPU_CLKC_P1_SEL] = &s4_vpu_clkc_p1_sel.hw, + [CLKID_VPU_CLKC_P1_DIV] = &s4_vpu_clkc_p1_div.hw, + [CLKID_VPU_CLKC_P1] = &s4_vpu_clkc_p1.hw, + [CLKID_VPU_CLKC_SEL] = &s4_vpu_clkc_sel.hw, + [CLKID_VAPB_0_SEL] = &s4_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &s4_vapb_0_div.hw, + [CLKID_VAPB_0] = &s4_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &s4_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &s4_vapb_1_div.hw, + [CLKID_VAPB_1] = &s4_vapb_1.hw, + [CLKID_VAPB] = &s4_vapb.hw, + [CLKID_GE2D] = &s4_ge2d.hw, + [CLKID_VDIN_MEAS_SEL] = &s4_vdin_meas_sel.hw, + [CLKID_VDIN_MEAS_DIV] = &s4_vdin_meas_div.hw, + [CLKID_VDIN_MEAS] = &s4_vdin_meas.hw, + [CLKID_SD_EMMC_C_CLK_SEL] = &s4_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK_DIV] = &s4_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C] = &s4_sd_emmc_c_clk0.hw, + [CLKID_SD_EMMC_A_CLK_SEL] = &s4_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK_DIV] = &s4_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A] = &s4_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK_SEL] = &s4_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK_DIV] = &s4_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B] = &s4_sd_emmc_b_clk0.hw, + [CLKID_SPICC0_SEL] = &s4_spicc0_sel.hw, + [CLKID_SPICC0_DIV] = &s4_spicc0_div.hw, + [CLKID_SPICC0_EN] = &s4_spicc0_en.hw, + [CLKID_PWM_A_SEL] = &s4_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &s4_pwm_a_div.hw, + [CLKID_PWM_A] = &s4_pwm_a.hw, + [CLKID_PWM_B_SEL] = &s4_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &s4_pwm_b_div.hw, + [CLKID_PWM_B] = &s4_pwm_b.hw, + [CLKID_PWM_C_SEL] = &s4_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &s4_pwm_c_div.hw, + [CLKID_PWM_C] = &s4_pwm_c.hw, + [CLKID_PWM_D_SEL] = &s4_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &s4_pwm_d_div.hw, + [CLKID_PWM_D] = &s4_pwm_d.hw, + [CLKID_PWM_E_SEL] = &s4_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &s4_pwm_e_div.hw, + [CLKID_PWM_E] = &s4_pwm_e.hw, + [CLKID_PWM_F_SEL] = &s4_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &s4_pwm_f_div.hw, + [CLKID_PWM_F] = &s4_pwm_f.hw, + [CLKID_PWM_G_SEL] = &s4_pwm_g_sel.hw, + [CLKID_PWM_G_DIV] = &s4_pwm_g_div.hw, + [CLKID_PWM_G] = &s4_pwm_g.hw, + [CLKID_PWM_H_SEL] = &s4_pwm_h_sel.hw, + [CLKID_PWM_H_DIV] = &s4_pwm_h_div.hw, + [CLKID_PWM_H] = &s4_pwm_h.hw, + [CLKID_PWM_I_SEL] = &s4_pwm_i_sel.hw, + [CLKID_PWM_I_DIV] = &s4_pwm_i_div.hw, + [CLKID_PWM_I] = &s4_pwm_i.hw, + [CLKID_PWM_J_SEL] = &s4_pwm_j_sel.hw, + [CLKID_PWM_J_DIV] = &s4_pwm_j_div.hw, + [CLKID_PWM_J] = &s4_pwm_j.hw, + [CLKID_SARADC_SEL] = &s4_saradc_sel.hw, + [CLKID_SARADC_DIV] = &s4_saradc_div.hw, + [CLKID_SARADC] = &s4_saradc.hw, + [CLKID_GEN_SEL] = &s4_gen_clk_sel.hw, + [CLKID_GEN_DIV] = &s4_gen_clk_div.hw, + [CLKID_GEN] = &s4_gen_clk.hw, + [CLKID_DDR] = &s4_ddr.hw, + [CLKID_DOS] = &s4_dos.hw, + [CLKID_ETHPHY] = &s4_ethphy.hw, + [CLKID_MALI] = &s4_mali.hw, + [CLKID_AOCPU] = &s4_aocpu.hw, + [CLKID_AUCPU] = &s4_aucpu.hw, + [CLKID_CEC] = &s4_cec.hw, + [CLKID_SDEMMC_A] = &s4_sdemmca.hw, + [CLKID_SDEMMC_B] = &s4_sdemmcb.hw, + [CLKID_NAND] = &s4_nand.hw, + [CLKID_SMARTCARD] = &s4_smartcard.hw, + [CLKID_ACODEC] = &s4_acodec.hw, + [CLKID_SPIFC] = &s4_spifc.hw, + [CLKID_MSR] = &s4_msr_clk.hw, + [CLKID_IR_CTRL] = &s4_ir_ctrl.hw, + [CLKID_AUDIO] = &s4_audio.hw, + [CLKID_ETH] = &s4_eth.hw, + [CLKID_UART_A] = &s4_uart_a.hw, + [CLKID_UART_B] = &s4_uart_b.hw, + [CLKID_UART_C] = &s4_uart_c.hw, + [CLKID_UART_D] = &s4_uart_d.hw, + [CLKID_UART_E] = &s4_uart_e.hw, + [CLKID_AIFIFO] = &s4_aififo.hw, + [CLKID_TS_DDR] = &s4_ts_ddr.hw, + [CLKID_TS_PLL] = &s4_ts_pll.hw, + [CLKID_G2D] = &s4_g2d.hw, + [CLKID_SPICC0] = &s4_spicc0.hw, + [CLKID_USB] = &s4_usb.hw, + [CLKID_I2C_M_A] = &s4_i2c_m_a.hw, + [CLKID_I2C_M_B] = &s4_i2c_m_b.hw, + [CLKID_I2C_M_C] = &s4_i2c_m_c.hw, + [CLKID_I2C_M_D] = &s4_i2c_m_d.hw, + [CLKID_I2C_M_E] = &s4_i2c_m_e.hw, + [CLKID_HDMITX_APB] = &s4_hdmitx_apb.hw, + [CLKID_I2C_S_A] = &s4_i2c_s_a.hw, + [CLKID_USB1_TO_DDR] = &s4_usb1_to_ddr.hw, + [CLKID_HDCP22] = &s4_hdcp22.hw, + [CLKID_MMC_APB] = &s4_mmc_apb.hw, + [CLKID_RSA] = &s4_rsa.hw, + [CLKID_CPU_DEBUG] = &s4_cpu_debug.hw, + [CLKID_VPU_INTR] = &s4_vpu_intr.hw, + [CLKID_DEMOD] = &s4_demod.hw, + [CLKID_SAR_ADC] = &s4_sar_adc.hw, + [CLKID_GIC] = &s4_gic.hw, + [CLKID_PWM_AB] = &s4_pwm_ab.hw, + [CLKID_PWM_CD] = &s4_pwm_cd.hw, + [CLKID_PWM_EF] = &s4_pwm_ef.hw, + [CLKID_PWM_GH] = &s4_pwm_gh.hw, + [CLKID_PWM_IJ] = &s4_pwm_ij.hw, + [CLKID_HDCP22_ESMCLK_SEL] = &s4_hdcp22_esmclk_sel.hw, + [CLKID_HDCP22_ESMCLK_DIV] = &s4_hdcp22_esmclk_div.hw, + [CLKID_HDCP22_ESMCLK] = &s4_hdcp22_esmclk.hw, + [CLKID_HDCP22_SKPCLK_SEL] = &s4_hdcp22_skpclk_sel.hw, + [CLKID_HDCP22_SKPCLK_DIV] = &s4_hdcp22_skpclk_div.hw, + [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk.hw, + [CLKID_CTS_ENCL_SEL] = &s4_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &s4_cts_encl.hw, + [CLKID_CDAC_SEL] = &s4_cdac_sel.hw, + [CLKID_CDAC_DIV] = &s4_cdac_div.hw, + [CLKID_CDAC] = &s4_cdac.hw, + [CLKID_DEMOD_CORE_SEL] = &s4_demod_core_sel.hw, + [CLKID_DEMOD_CORE_DIV] = &s4_demod_core_div.hw, + [CLKID_DEMOD_CORE] = &s4_demod_core.hw, + [CLKID_ADC_EXTCLK_IN_SEL] = &s4_adc_extclk_in_sel.hw, + [CLKID_ADC_EXTCLK_IN_DIV] = &s4_adc_extclk_in_div.hw, + [CLKID_ADC_EXTCLK_IN] = &s4_adc_extclk_in.hw, +}; + +static const struct meson_clkc_data s4_peripherals_clkc_data = { + .hw_clks = { + .hws = s4_peripherals_hw_clks, + .num = ARRAY_SIZE(s4_peripherals_hw_clks), + }, +}; + +static const struct of_device_id s4_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,s4-peripherals-clkc", + .data = &s4_peripherals_clkc_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, s4_peripherals_clkc_match_table); + +static struct platform_driver s4_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "s4-peripherals-clkc", + .of_match_table = s4_peripherals_clkc_match_table, + }, +}; +module_platform_driver(s4_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic S4 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Yu Tu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c new file mode 100644 index 000000000..56ce6f566 --- /dev/null +++ b/drivers/clk/meson/s4-pll.c @@ -0,0 +1,831 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Amlogic S4 PLL Clock Controller Driver + * + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "meson-clkc-utils.h" +#include + +#define ANACTRL_FIXPLL_CTRL0 0x040 +#define ANACTRL_FIXPLL_CTRL1 0x044 +#define ANACTRL_FIXPLL_CTRL3 0x04c +#define ANACTRL_GP0PLL_CTRL0 0x080 +#define ANACTRL_GP0PLL_CTRL1 0x084 +#define ANACTRL_GP0PLL_CTRL2 0x088 +#define ANACTRL_GP0PLL_CTRL3 0x08c +#define ANACTRL_GP0PLL_CTRL4 0x090 +#define ANACTRL_GP0PLL_CTRL5 0x094 +#define ANACTRL_GP0PLL_CTRL6 0x098 +#define ANACTRL_HIFIPLL_CTRL0 0x100 +#define ANACTRL_HIFIPLL_CTRL1 0x104 +#define ANACTRL_HIFIPLL_CTRL2 0x108 +#define ANACTRL_HIFIPLL_CTRL3 0x10c +#define ANACTRL_HIFIPLL_CTRL4 0x110 +#define ANACTRL_HIFIPLL_CTRL5 0x114 +#define ANACTRL_HIFIPLL_CTRL6 0x118 +#define ANACTRL_MPLL_CTRL0 0x180 +#define ANACTRL_MPLL_CTRL1 0x184 +#define ANACTRL_MPLL_CTRL2 0x188 +#define ANACTRL_MPLL_CTRL3 0x18c +#define ANACTRL_MPLL_CTRL4 0x190 +#define ANACTRL_MPLL_CTRL5 0x194 +#define ANACTRL_MPLL_CTRL6 0x198 +#define ANACTRL_MPLL_CTRL7 0x19c +#define ANACTRL_MPLL_CTRL8 0x1a0 +#define ANACTRL_HDMIPLL_CTRL0 0x1c0 + +/* + * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode. + * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable + * in the kernel phase. Write of fixed PLL-related register will cause the system to crash. + * Meanwhile, these clock won't ever change at runtime. + * For the above reasons, we can only use ro_ops for fixed PLL related clocks. + */ +static struct clk_regmap s4_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .frac = { + .reg_off = ANACTRL_FIXPLL_CTRL1, + .shift = 0, + .width = 17, + }, + .n = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_fixed_factor s4_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div2_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div3_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div2p5_div = { + .mult = 2, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div2p5_div.hw + }, + .num_parents = 1, + }, +}; + +static const struct pll_mult_range s4_gp0_pll_mult_range = { + .min = 125, + .max = 250, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence s4_gp0_pll_init_regs[] = { + { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 }, + { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 }, + { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, + { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 }, + { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x39272000 }, + { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap s4_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + .init_regs = s4_gp0_pll_init_regs, + .init_count = ARRAY_SIZE(s4_gp0_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_GP0PLL_CTRL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence s4_hifi_pll_init_regs[] = { + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 }, + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x39272000 }, + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap s4_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = ANACTRL_HIFIPLL_CTRL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + .init_regs = s4_hifi_pll_init_regs, + .init_count = ARRAY_SIZE(s4_hifi_pll_init_regs), + .frac_max = 100000, + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HIFIPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HDMIPLL_CTRL0, + .shift = 16, + .width = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HDMIPLL_CTRL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_mpll_50m_div = { + .mult = 1, + .div = 80, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll_50m = { + .data = &(struct clk_regmap_mux_data){ + .offset = ANACTRL_FIXPLL_CTRL3, + .mask = 0x1, + .shift = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &s4_mpll_50m_div.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_fixed_factor s4_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static const struct reg_sequence s4_mpll0_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 29, + .width = 1, + }, + .init_regs = s4_mpll0_init_regs, + .init_count = ARRAY_SIZE(s4_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll1_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 29, + .width = 1, + }, + .init_regs = s4_mpll1_init_regs, + .init_count = ARRAY_SIZE(s4_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll2_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 29, + .width = 1, + }, + .init_regs = s4_mpll2_init_regs, + .init_count = ARRAY_SIZE(s4_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll3_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 29, + .width = 1, + }, + .init_regs = s4_mpll3_init_regs, + .init_count = ARRAY_SIZE(s4_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Array of all clocks provided by this provider */ +static struct clk_hw *s4_pll_hw_clks[] = { + [CLKID_FIXED_PLL_DCO] = &s4_fixed_pll_dco.hw, + [CLKID_FIXED_PLL] = &s4_fixed_pll.hw, + [CLKID_FCLK_DIV2_DIV] = &s4_fclk_div2_div.hw, + [CLKID_FCLK_DIV2] = &s4_fclk_div2.hw, + [CLKID_FCLK_DIV3_DIV] = &s4_fclk_div3_div.hw, + [CLKID_FCLK_DIV3] = &s4_fclk_div3.hw, + [CLKID_FCLK_DIV4_DIV] = &s4_fclk_div4_div.hw, + [CLKID_FCLK_DIV4] = &s4_fclk_div4.hw, + [CLKID_FCLK_DIV5_DIV] = &s4_fclk_div5_div.hw, + [CLKID_FCLK_DIV5] = &s4_fclk_div5.hw, + [CLKID_FCLK_DIV7_DIV] = &s4_fclk_div7_div.hw, + [CLKID_FCLK_DIV7] = &s4_fclk_div7.hw, + [CLKID_FCLK_DIV2P5_DIV] = &s4_fclk_div2p5_div.hw, + [CLKID_FCLK_DIV2P5] = &s4_fclk_div2p5.hw, + [CLKID_GP0_PLL_DCO] = &s4_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &s4_gp0_pll.hw, + [CLKID_HIFI_PLL_DCO] = &s4_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &s4_hifi_pll.hw, + [CLKID_HDMI_PLL_DCO] = &s4_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &s4_hdmi_pll_od.hw, + [CLKID_HDMI_PLL] = &s4_hdmi_pll.hw, + [CLKID_MPLL_50M_DIV] = &s4_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &s4_mpll_50m.hw, + [CLKID_MPLL_PREDIV] = &s4_mpll_prediv.hw, + [CLKID_MPLL0_DIV] = &s4_mpll0_div.hw, + [CLKID_MPLL0] = &s4_mpll0.hw, + [CLKID_MPLL1_DIV] = &s4_mpll1_div.hw, + [CLKID_MPLL1] = &s4_mpll1.hw, + [CLKID_MPLL2_DIV] = &s4_mpll2_div.hw, + [CLKID_MPLL2] = &s4_mpll2.hw, + [CLKID_MPLL3_DIV] = &s4_mpll3_div.hw, + [CLKID_MPLL3] = &s4_mpll3.hw, +}; + +static const struct reg_sequence s4_pll_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, +}; + +static const struct meson_clkc_data s4_pll_clkc_data = { + .hw_clks = { + .hws = s4_pll_hw_clks, + .num = ARRAY_SIZE(s4_pll_hw_clks), + }, + .init_regs = s4_pll_init_regs, + .init_count = ARRAY_SIZE(s4_pll_init_regs), +}; + +static const struct of_device_id s4_pll_clkc_match_table[] = { + { + .compatible = "amlogic,s4-pll-clkc", + .data = &s4_pll_clkc_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, s4_pll_clkc_match_table); + +static struct platform_driver s4_pll_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "s4-pll-clkc", + .of_match_table = s4_pll_clkc_match_table, + }, +}; +module_platform_driver(s4_pll_clkc_driver); + +MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); +MODULE_AUTHOR("Yu Tu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c new file mode 100644 index 000000000..4ba3d8281 --- /dev/null +++ b/drivers/clk/meson/sclk-div.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + * + * Sample clock generator divider: + * This HW divider gates with value 0 but is otherwise a zero based divider: + * + * val >= 1 + * divider = val + 1 + * + * The duty cycle may also be set for the LR clock variant. The duty cycle + * ratio is: + * + * hi = [0 - val] + * duty_cycle = (1 + hi) / (1 + val) + */ + +#include +#include + +#include "clk-regmap.h" +#include "sclk-div.h" + +static inline struct meson_sclk_div_data * +meson_sclk_div_data(struct clk_regmap *clk) +{ + return (struct meson_sclk_div_data *)clk->data; +} + +static int sclk_div_maxval(struct meson_sclk_div_data *sclk) +{ + return (1 << sclk->div.width) - 1; +} + +static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk) +{ + return sclk_div_maxval(sclk) + 1; +} + +static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate, + unsigned long prate, int maxdiv) +{ + int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate); + + return clamp(div, 2, maxdiv); +} + +static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *prate, + struct meson_sclk_div_data *sclk) +{ + struct clk_hw *parent = clk_hw_get_parent(hw); + int bestdiv = 0, i; + unsigned long maxdiv, now, parent_now; + unsigned long best = 0, best_parent = 0; + + if (!rate) + rate = 1; + + maxdiv = sclk_div_maxdiv(sclk); + + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) + return sclk_div_getdiv(hw, rate, *prate, maxdiv); + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 2; i <= maxdiv; i++) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + if (rate * i == *prate) + return i; + + parent_now = clk_hw_round_rate(parent, rate * i); + now = DIV_ROUND_UP_ULL((u64)parent_now, i); + + if (abs(rate - now) < abs(rate - best)) { + bestdiv = i; + best = now; + best_parent = parent_now; + } + } + + if (!bestdiv) + bestdiv = sclk_div_maxdiv(sclk); + else + *prate = best_parent; + + return bestdiv; +} + +static int sclk_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + int div; + + div = sclk_div_bestdiv(hw, req->rate, &req->best_parent_rate, sclk); + req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div); + + return 0; +} + +static void sclk_apply_ratio(struct clk_regmap *clk, + struct meson_sclk_div_data *sclk) +{ + unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div * + sclk->cached_duty.num, + sclk->cached_duty.den); + + if (hi) + hi -= 1; + + meson_parm_write(clk->map, &sclk->hi, hi); +} + +static int sclk_div_set_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + if (MESON_PARM_APPLICABLE(&sclk->hi)) { + memcpy(&sclk->cached_duty, duty, sizeof(*duty)); + sclk_apply_ratio(clk, sclk); + } + + return 0; +} + +static int sclk_div_get_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + int hi; + + if (!MESON_PARM_APPLICABLE(&sclk->hi)) { + duty->num = 1; + duty->den = 2; + return 0; + } + + hi = meson_parm_read(clk->map, &sclk->hi); + duty->num = hi + 1; + duty->den = sclk->cached_div; + return 0; +} + +static void sclk_apply_divider(struct clk_regmap *clk, + struct meson_sclk_div_data *sclk) +{ + if (MESON_PARM_APPLICABLE(&sclk->hi)) + sclk_apply_ratio(clk, sclk); + + meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1); +} + +static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + unsigned long maxdiv = sclk_div_maxdiv(sclk); + + sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv); + + if (clk_hw_is_enabled(hw)) + sclk_apply_divider(clk, sclk); + + return 0; +} + +static unsigned long sclk_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div); +} + +static int sclk_div_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + sclk_apply_divider(clk, sclk); + + return 0; +} + +static void sclk_div_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + meson_parm_write(clk->map, &sclk->div, 0); +} + +static int sclk_div_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + if (meson_parm_read(clk->map, &sclk->div)) + return 1; + + return 0; +} + +static int sclk_div_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + unsigned int val; + int ret; + + ret = clk_regmap_init(hw); + if (ret) + return ret; + + val = meson_parm_read(clk->map, &sclk->div); + + /* if the divider is initially disabled, assume max */ + if (!val) + sclk->cached_div = sclk_div_maxdiv(sclk); + else + sclk->cached_div = val + 1; + + sclk_div_get_duty_cycle(hw, &sclk->cached_duty); + + return 0; +} + +const struct clk_ops meson_sclk_div_ops = { + .recalc_rate = sclk_div_recalc_rate, + .determine_rate = sclk_div_determine_rate, + .set_rate = sclk_div_set_rate, + .enable = sclk_div_enable, + .disable = sclk_div_disable, + .is_enabled = sclk_div_is_enabled, + .get_duty_cycle = sclk_div_get_duty_cycle, + .set_duty_cycle = sclk_div_set_duty_cycle, + .init = sclk_div_init, +}; +EXPORT_SYMBOL_NS_GPL(meson_sclk_div_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic Sample divider driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/sclk-div.h b/drivers/clk/meson/sclk-div.h new file mode 100644 index 000000000..b64b2a320 --- /dev/null +++ b/drivers/clk/meson/sclk-div.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_SCLK_DIV_H +#define __MESON_SCLK_DIV_H + +#include +#include "parm.h" + +struct meson_sclk_div_data { + struct parm div; + struct parm hi; + unsigned int cached_div; + struct clk_duty cached_duty; +}; + +extern const struct clk_ops meson_sclk_div_ops; + +#endif /* __MESON_SCLK_DIV_H */ diff --git a/drivers/clk/meson/t7-peripherals.c b/drivers/clk/meson/t7-peripherals.c new file mode 100644 index 000000000..214db7850 --- /dev/null +++ b/drivers/clk/meson/t7-peripherals.c @@ -0,0 +1,1271 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + */ + +#include +#include +#include "clk-dualdiv.h" +#include "clk-regmap.h" +#include "meson-clkc-utils.h" +#include + +#define RTC_BY_OSCIN_CTRL0 0x8 +#define RTC_BY_OSCIN_CTRL1 0xc +#define RTC_CTRL 0x10 +#define SYS_CLK_CTRL0 0x40 +#define SYS_CLK_EN0_REG0 0x44 +#define SYS_CLK_EN0_REG1 0x48 +#define SYS_CLK_EN0_REG2 0x4c +#define SYS_CLK_EN0_REG3 0x50 +#define CECA_CTRL0 0x88 +#define CECA_CTRL1 0x8c +#define CECB_CTRL0 0x90 +#define CECB_CTRL1 0x94 +#define SC_CLK_CTRL 0x98 +#define DSPA_CLK_CTRL0 0x9c +#define DSPB_CLK_CTRL0 0xa0 +#define CLK12_24_CTRL 0xa8 +#define ANAKIN_CLK_CTRL 0xac +#define MIPI_CSI_PHY_CLK_CTRL 0x10c +#define MIPI_ISP_CLK_CTRL 0x110 +#define TS_CLK_CTRL 0x158 +#define MALI_CLK_CTRL 0x15c +#define ETH_CLK_CTRL 0x164 +#define NAND_CLK_CTRL 0x168 +#define SD_EMMC_CLK_CTRL 0x16c +#define SPICC_CLK_CTRL 0x174 +#define SAR_CLK_CTRL0 0x17c +#define PWM_CLK_AB_CTRL 0x180 +#define PWM_CLK_CD_CTRL 0x184 +#define PWM_CLK_EF_CTRL 0x188 +#define PWM_CLK_AO_AB_CTRL 0x1a0 +#define PWM_CLK_AO_CD_CTRL 0x1a4 +#define PWM_CLK_AO_EF_CTRL 0x1a8 +#define PWM_CLK_AO_GH_CTRL 0x1ac +#define SPICC_CLK_CTRL1 0x1c0 +#define SPICC_CLK_CTRL2 0x1c4 + +#define T7_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \ + MESON_COMP_SEL(t7_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0) + +#define T7_COMP_DIV(_name, _reg, _shift, _width) \ + MESON_COMP_DIV(t7_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT) + +#define T7_COMP_GATE(_name, _reg, _bit, _iflags) \ + MESON_COMP_GATE(t7_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags)) + +static struct clk_regmap t7_rtc_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_duandiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param t7_dualdiv_table[] = { + { + .n1 = 733, .m1 = 8, + .n2 = 732, .m2 = 11, + .dual = 1, + }, + {} +}; + +static struct clk_regmap t7_rtc_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_rtc_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_div.hw, + &t7_rtc_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_rtc_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_rtc_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_rtc = { + .data = &(struct clk_regmap_mux_data) { + .offset = RTC_CTRL, + .mask = 0x3, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc", + .ops = &clk_regmap_mux_ops, + /* + * xtal is also on parent input #3 but that it is not useful to CCF since + * the same parent is available with parent input #0 + */ + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &t7_rtc_dualdiv.hw }, + { .fw_name = "ext_rtc", }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ceca_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECA_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECA_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECA_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECA_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECA_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_div.hw, + &t7_ceca_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_ceca_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECA_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_ceca = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECA_CTRL1, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ceca_dualdiv.hw, + &t7_rtc.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_in = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "cecb_dualdiv_in", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CECB_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CECB_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CECB_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CECB_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CECB_CTRL0, + .shift = 28, + .width = 1, + }, + .table = t7_dualdiv_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_in.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CTRL1, + .mask = 0x1, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_div.hw, + &t7_cecb_dualdiv_in.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb_dualdiv = { + .data = &(struct clk_regmap_gate_data){ + .offset = CECB_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_dualdiv", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_cecb = { + .data = &(struct clk_regmap_mux_data) { + .offset = CECB_CTRL1, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_cecb_dualdiv.hw, + &t7_rtc.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_sc_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "xtal", }, +}; + +static T7_COMP_SEL(sc, SC_CLK_CTRL, 9, 0x3, t7_sc_parents); +static T7_COMP_DIV(sc, SC_CLK_CTRL, 0, 8); +static T7_COMP_GATE(sc, SC_CLK_CTRL, 8, 0); + +static const struct clk_parent_data t7_dsp_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "hifi", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv7", }, + { .hw = &t7_rtc.hw }, +}; + +static T7_COMP_SEL(dspa_0, DSPA_CLK_CTRL0, 10, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspa_0, DSPA_CLK_CTRL0, 0, 10); +static T7_COMP_GATE(dspa_0, DSPA_CLK_CTRL0, 13, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(dspa_1, DSPA_CLK_CTRL0, 26, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspa_1, DSPA_CLK_CTRL0, 16, 10); +static T7_COMP_GATE(dspa_1, DSPA_CLK_CTRL0, 29, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_dspa = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPA_CLK_CTRL0, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspa", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_dspa_0.hw, + &t7_dspa_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static T7_COMP_SEL(dspb_0, DSPB_CLK_CTRL0, 10, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspb_0, DSPB_CLK_CTRL0, 0, 10); +static T7_COMP_GATE(dspb_0, DSPB_CLK_CTRL0, 13, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(dspb_1, DSPB_CLK_CTRL0, 26, 0x7, t7_dsp_parents); +static T7_COMP_DIV(dspb_1, DSPB_CLK_CTRL0, 16, 10); +static T7_COMP_GATE(dspb_1, DSPB_CLK_CTRL0, 29, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_dspb = { + .data = &(struct clk_regmap_mux_data){ + .offset = DSPB_CLK_CTRL0, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "dspb", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_dspb_0.hw, + &t7_dspb_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_24m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "24m", + .ops = &clk_regmap_gate_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor t7_24m_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "24m_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_24m.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_12m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "12m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_24m_div2.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_25m_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLK12_24_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "25m_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fix", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_25m = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLK12_24_CTRL, + .bit_idx = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "25m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_25m_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_anakin_parents[] = { + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv2", }, + { .fw_name = "vid_pll0", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "fdiv2p5", }, +}; + +static T7_COMP_SEL(anakin_0, ANAKIN_CLK_CTRL, 9, 0x7, t7_anakin_parents); +static T7_COMP_DIV(anakin_0, ANAKIN_CLK_CTRL, 0, 7); +static T7_COMP_GATE(anakin_0, ANAKIN_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(anakin_1, ANAKIN_CLK_CTRL, 25, 0x7, t7_anakin_parents); +static T7_COMP_DIV(anakin_1, ANAKIN_CLK_CTRL, 16, 7); +static T7_COMP_GATE(anakin_1, ANAKIN_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_anakin_01_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = ANAKIN_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "anakin_01_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_anakin_0.hw, + &t7_anakin_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT + }, +}; + +static struct clk_regmap t7_anakin = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANAKIN_CLK_CTRL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "anakin", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_anakin_01_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT + }, +}; + +static const struct clk_parent_data t7_mipi_csi_phy_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp1", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, +}; + +static T7_COMP_SEL(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7, t7_mipi_csi_phy_parents); +static T7_COMP_DIV(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mipi_csi_phy_0, MIPI_CSI_PHY_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 25, 0x7, t7_mipi_csi_phy_parents); +static T7_COMP_DIV(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 16, 7); +static T7_COMP_GATE(mipi_csi_phy_1, MIPI_CSI_PHY_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_mipi_csi_phy = { + .data = &(struct clk_regmap_mux_data){ + .offset = MIPI_CSI_PHY_CLK_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_csi_phy", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mipi_csi_phy_0.hw, + &t7_mipi_csi_phy_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_mipi_isp_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp1", }, +}; + +static T7_COMP_SEL(mipi_isp, MIPI_ISP_CLK_CTRL, 9, 0x7, t7_mipi_isp_parents); +static T7_COMP_DIV(mipi_isp, MIPI_ISP_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mipi_isp, MIPI_ISP_CLK_CTRL, 8, 0); + +static struct clk_regmap t7_ts_div = { + .data = &(struct clk_regmap_div_data){ + .offset = TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_ts = { + .data = &(struct clk_regmap_gate_data){ + .offset = TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_ts_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data t7_mali_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp0", }, + { .fw_name = "gp1", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, +}; + +static T7_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, t7_mali_parents); +static T7_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7); +static T7_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE); + +static T7_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, t7_mali_parents); +static T7_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7); +static T7_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE); + +static struct clk_regmap t7_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = MALI_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mali_0.hw, + &t7_mali_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * parent index 2, 3, 4, 5, 6 not connect any clock signal, + * the last parent connect external PAD + */ +static u32 t7_eth_rmii_parents_val_table[] = { 0, 1, 7 }; +static const struct clk_parent_data t7_eth_rmii_parents[] = { + { .fw_name = "fdiv2", }, + { .fw_name = "gp1", }, + { .fw_name = "ext_rmii", }, +}; + +static struct clk_regmap t7_eth_rmii_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = ETH_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .table = t7_eth_rmii_parents_val_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = t7_eth_rmii_parents, + .num_parents = ARRAY_SIZE(t7_eth_rmii_parents), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap t7_eth_rmii_div = { + .data = &(struct clk_regmap_div_data) { + .offset = ETH_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_eth_rmii_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_eth_rmii = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_rmii", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_eth_rmii_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_fdiv2_div8 = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data){ + .name = "fdiv2_div8", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "fdiv2", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_eth_125m = { + .data = &(struct clk_regmap_gate_data) { + .offset = ETH_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "eth_125m", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_fdiv2_div8.hw + }, + .num_parents = 1, + }, +}; + +static const struct clk_parent_data t7_sd_emmc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv3", }, + { .fw_name = "hifi", }, + { .fw_name = "fdiv2p5", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp0", }, +}; + +static T7_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL, 0, 7); +static T7_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL, 7, 0); + +static T7_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL, 25, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL, 16, 7); +static T7_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL, 23, 0); + +static T7_COMP_SEL(sd_emmc_c, NAND_CLK_CTRL, 9, 0x7, t7_sd_emmc_parents); +static T7_COMP_DIV(sd_emmc_c, NAND_CLK_CTRL, 0, 7); +static T7_COMP_GATE(sd_emmc_c, NAND_CLK_CTRL, 7, 0); + +static const struct clk_parent_data t7_spicc_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "sys", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, + { .fw_name = "fdiv2", }, + { .fw_name = "fdiv5", }, + { .fw_name = "fdiv7", }, + { .fw_name = "gp1", }, +}; + +static T7_COMP_SEL(spicc0, SPICC_CLK_CTRL, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc0, SPICC_CLK_CTRL, 0, 6); +static T7_COMP_GATE(spicc0, SPICC_CLK_CTRL, 6, 0); + +static T7_COMP_SEL(spicc1, SPICC_CLK_CTRL, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc1, SPICC_CLK_CTRL, 16, 6); +static T7_COMP_GATE(spicc1, SPICC_CLK_CTRL, 22, 0); + +static T7_COMP_SEL(spicc2, SPICC_CLK_CTRL1, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc2, SPICC_CLK_CTRL1, 0, 6); +static T7_COMP_GATE(spicc2, SPICC_CLK_CTRL1, 6, 0); + +static T7_COMP_SEL(spicc3, SPICC_CLK_CTRL1, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc3, SPICC_CLK_CTRL1, 16, 6); +static T7_COMP_GATE(spicc3, SPICC_CLK_CTRL1, 22, 0); + +static T7_COMP_SEL(spicc4, SPICC_CLK_CTRL2, 7, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc4, SPICC_CLK_CTRL2, 0, 6); +static T7_COMP_GATE(spicc4, SPICC_CLK_CTRL2, 6, 0); + +static T7_COMP_SEL(spicc5, SPICC_CLK_CTRL2, 23, 0x7, t7_spicc_parents); +static T7_COMP_DIV(spicc5, SPICC_CLK_CTRL2, 16, 6); +static T7_COMP_GATE(spicc5, SPICC_CLK_CTRL2, 22, 0); + +static const struct clk_parent_data t7_saradc_parents[] = { + { .fw_name = "xtal" }, + { .fw_name = "sys" }, +}; + +static T7_COMP_SEL(saradc, SAR_CLK_CTRL0, 9, 0x1, t7_saradc_parents); +static T7_COMP_DIV(saradc, SAR_CLK_CTRL0, 0, 8); +static T7_COMP_GATE(saradc, SAR_CLK_CTRL0, 8, 0); + +static const struct clk_parent_data t7_pwm_parents[] = { + { .fw_name = "xtal", }, + { .fw_name = "vid_pll0", }, + { .fw_name = "fdiv4", }, + { .fw_name = "fdiv3", }, +}; + +static T7_COMP_SEL(pwm_a, PWM_CLK_AB_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_a, PWM_CLK_AB_CTRL, 0, 8); +static T7_COMP_GATE(pwm_a, PWM_CLK_AB_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_b, PWM_CLK_AB_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_b, PWM_CLK_AB_CTRL, 16, 8); +static T7_COMP_GATE(pwm_b, PWM_CLK_AB_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_c, PWM_CLK_CD_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_c, PWM_CLK_CD_CTRL, 0, 8); +static T7_COMP_GATE(pwm_c, PWM_CLK_CD_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_d, PWM_CLK_CD_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_d, PWM_CLK_CD_CTRL, 16, 8); +static T7_COMP_GATE(pwm_d, PWM_CLK_CD_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_e, PWM_CLK_EF_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_e, PWM_CLK_EF_CTRL, 0, 8); +static T7_COMP_GATE(pwm_e, PWM_CLK_EF_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_f, PWM_CLK_EF_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_f, PWM_CLK_EF_CTRL, 16, 8); +static T7_COMP_GATE(pwm_f, PWM_CLK_EF_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_a, PWM_CLK_AO_AB_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_b, PWM_CLK_AO_AB_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_c, PWM_CLK_AO_CD_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_d, PWM_CLK_AO_CD_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_e, PWM_CLK_AO_EF_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_f, PWM_CLK_AO_EF_CTRL, 24, 0); + +static T7_COMP_SEL(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 9, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 0, 8); +static T7_COMP_GATE(pwm_ao_g, PWM_CLK_AO_GH_CTRL, 8, 0); + +static T7_COMP_SEL(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 25, 0x3, t7_pwm_parents); +static T7_COMP_DIV(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 16, 8); +static T7_COMP_GATE(pwm_ao_h, PWM_CLK_AO_GH_CTRL, 24, 0); + +static const struct clk_parent_data t7_sys_pclk_parents = { .fw_name = "sys" }; + +#define T7_SYS_PCLK(_name, _reg, _bit, _flags) \ + MESON_PCLK(t7_##_name, _reg, _bit, &t7_sys_pclk_parents, _flags) + +static T7_SYS_PCLK(sys_ddr, SYS_CLK_EN0_REG0, 0, 0); +static T7_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1, 0); +static T7_SYS_PCLK(sys_mipi_dsi_a, SYS_CLK_EN0_REG0, 2, 0); +static T7_SYS_PCLK(sys_mipi_dsi_b, SYS_CLK_EN0_REG0, 3, 0); +static T7_SYS_PCLK(sys_ethphy, SYS_CLK_EN0_REG0, 4, 0); +static T7_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6, 0); +static T7_SYS_PCLK(sys_aocpu, SYS_CLK_EN0_REG0, 13, 0); +static T7_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14, 0); +static T7_SYS_PCLK(sys_cec, SYS_CLK_EN0_REG0, 16, 0); +static T7_SYS_PCLK(sys_gdc, SYS_CLK_EN0_REG0, 17, 0); +static T7_SYS_PCLK(sys_deswarp, SYS_CLK_EN0_REG0, 18, 0); +static T7_SYS_PCLK(sys_ampipe_nand, SYS_CLK_EN0_REG0, 19, 0); +static T7_SYS_PCLK(sys_ampipe_eth, SYS_CLK_EN0_REG0, 20, 0); +static T7_SYS_PCLK(sys_am2axi0, SYS_CLK_EN0_REG0, 21, 0); +static T7_SYS_PCLK(sys_am2axi1, SYS_CLK_EN0_REG0, 22, 0); +static T7_SYS_PCLK(sys_am2axi2, SYS_CLK_EN0_REG0, 23, 0); +static T7_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24, 0); +static T7_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25, 0); +static T7_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26, 0); +static T7_SYS_PCLK(sys_smartcard, SYS_CLK_EN0_REG0, 27, 0); +static T7_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28, 0); +static T7_SYS_PCLK(sys_spifc, SYS_CLK_EN0_REG0, 29, 0); +static T7_SYS_PCLK(sys_msr_clk, SYS_CLK_EN0_REG0, 30, 0); +static T7_SYS_PCLK(sys_ir_ctrl, SYS_CLK_EN0_REG0, 31, 0); +static T7_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0, 0); +static T7_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3, 0); +static T7_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5, 0); +static T7_SYS_PCLK(sys_uart_b, SYS_CLK_EN0_REG1, 6, 0); +static T7_SYS_PCLK(sys_uart_c, SYS_CLK_EN0_REG1, 7, 0); +static T7_SYS_PCLK(sys_uart_d, SYS_CLK_EN0_REG1, 8, 0); +static T7_SYS_PCLK(sys_uart_e, SYS_CLK_EN0_REG1, 9, 0); +static T7_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10, 0); +static T7_SYS_PCLK(sys_aififo, SYS_CLK_EN0_REG1, 11, 0); +static T7_SYS_PCLK(sys_spicc2, SYS_CLK_EN0_REG1, 12, 0); +static T7_SYS_PCLK(sys_spicc3, SYS_CLK_EN0_REG1, 13, 0); +static T7_SYS_PCLK(sys_spicc4, SYS_CLK_EN0_REG1, 14, 0); +static T7_SYS_PCLK(sys_ts_a73, SYS_CLK_EN0_REG1, 15, 0); +static T7_SYS_PCLK(sys_ts_a53, SYS_CLK_EN0_REG1, 16, 0); +static T7_SYS_PCLK(sys_spicc5, SYS_CLK_EN0_REG1, 17, 0); +static T7_SYS_PCLK(sys_g2d, SYS_CLK_EN0_REG1, 20, 0); +static T7_SYS_PCLK(sys_spicc0, SYS_CLK_EN0_REG1, 21, 0); +static T7_SYS_PCLK(sys_spicc1, SYS_CLK_EN0_REG1, 22, 0); +static T7_SYS_PCLK(sys_pcie, SYS_CLK_EN0_REG1, 24, 0); +static T7_SYS_PCLK(sys_usb, SYS_CLK_EN0_REG1, 26, 0); +static T7_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27, 0); +static T7_SYS_PCLK(sys_i2c_ao_a, SYS_CLK_EN0_REG1, 28, 0); +static T7_SYS_PCLK(sys_i2c_ao_b, SYS_CLK_EN0_REG1, 29, 0); +static T7_SYS_PCLK(sys_i2c_m_a, SYS_CLK_EN0_REG1, 30, 0); +static T7_SYS_PCLK(sys_i2c_m_b, SYS_CLK_EN0_REG1, 31, 0); +static T7_SYS_PCLK(sys_i2c_m_c, SYS_CLK_EN0_REG2, 0, 0); +static T7_SYS_PCLK(sys_i2c_m_d, SYS_CLK_EN0_REG2, 1, 0); +static T7_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2, 0); +static T7_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3, 0); +static T7_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4, 0); +static T7_SYS_PCLK(sys_i2c_s_a, SYS_CLK_EN0_REG2, 5, 0); +static T7_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG2, 8, 0); +static T7_SYS_PCLK(sys_mmc_apb, SYS_CLK_EN0_REG2, 11, 0); +static T7_SYS_PCLK(sys_mipi_isp_pclk, SYS_CLK_EN0_REG2, 17, 0); +static T7_SYS_PCLK(sys_rsa, SYS_CLK_EN0_REG2, 18, 0); +static T7_SYS_PCLK(sys_pclk_sys_apb, SYS_CLK_EN0_REG2, 19, 0); +static T7_SYS_PCLK(sys_a73pclk_apb, SYS_CLK_EN0_REG2, 20, 0); +static T7_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21, 0); +static T7_SYS_PCLK(sys_dspb, SYS_CLK_EN0_REG2, 22, 0); +static T7_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25, 0); +static T7_SYS_PCLK(sys_sar_adc, SYS_CLK_EN0_REG2, 28, 0); +/* + * sys_gic provides the clock for GIC(Generic Interrupt Controller). + * After clock is disabled, The GIC cannot work properly. At present, the driver + * used by our GIC is the public driver in kernel, and there is no management + * clock in the driver. + */ +static T7_SYS_PCLK(sys_gic, SYS_CLK_EN0_REG2, 30, CLK_IS_CRITICAL); +static T7_SYS_PCLK(sys_ts_gpu, SYS_CLK_EN0_REG2, 31, 0); +static T7_SYS_PCLK(sys_ts_nna, SYS_CLK_EN0_REG3, 0, 0); +static T7_SYS_PCLK(sys_ts_vpu, SYS_CLK_EN0_REG3, 1, 0); +static T7_SYS_PCLK(sys_ts_hevc, SYS_CLK_EN0_REG3, 2, 0); +static T7_SYS_PCLK(sys_pwm_ao_ab, SYS_CLK_EN0_REG3, 3, 0); +static T7_SYS_PCLK(sys_pwm_ao_cd, SYS_CLK_EN0_REG3, 4, 0); +static T7_SYS_PCLK(sys_pwm_ao_ef, SYS_CLK_EN0_REG3, 5, 0); +static T7_SYS_PCLK(sys_pwm_ao_gh, SYS_CLK_EN0_REG3, 6, 0); +static T7_SYS_PCLK(sys_pwm_ab, SYS_CLK_EN0_REG3, 7, 0); +static T7_SYS_PCLK(sys_pwm_cd, SYS_CLK_EN0_REG3, 8, 0); +static T7_SYS_PCLK(sys_pwm_ef, SYS_CLK_EN0_REG3, 9, 0); + +/* Array of all clocks registered by this provider */ +static struct clk_hw *t7_peripherals_hw_clks[] = { + [CLKID_RTC_DUALDIV_IN] = &t7_rtc_dualdiv_in.hw, + [CLKID_RTC_DUALDIV_DIV] = &t7_rtc_dualdiv_div.hw, + [CLKID_RTC_DUALDIV_SEL] = &t7_rtc_dualdiv_sel.hw, + [CLKID_RTC_DUALDIV] = &t7_rtc_dualdiv.hw, + [CLKID_RTC] = &t7_rtc.hw, + [CLKID_CECA_DUALDIV_IN] = &t7_ceca_dualdiv_in.hw, + [CLKID_CECA_DUALDIV_DIV] = &t7_ceca_dualdiv_div.hw, + [CLKID_CECA_DUALDIV_SEL] = &t7_ceca_dualdiv_sel.hw, + [CLKID_CECA_DUALDIV] = &t7_ceca_dualdiv.hw, + [CLKID_CECA] = &t7_ceca.hw, + [CLKID_CECB_DUALDIV_IN] = &t7_cecb_dualdiv_in.hw, + [CLKID_CECB_DUALDIV_DIV] = &t7_cecb_dualdiv_div.hw, + [CLKID_CECB_DUALDIV_SEL] = &t7_cecb_dualdiv_sel.hw, + [CLKID_CECB_DUALDIV] = &t7_cecb_dualdiv.hw, + [CLKID_CECB] = &t7_cecb.hw, + [CLKID_SC_SEL] = &t7_sc_sel.hw, + [CLKID_SC_DIV] = &t7_sc_div.hw, + [CLKID_SC] = &t7_sc.hw, + [CLKID_DSPA_0_SEL] = &t7_dspa_0_sel.hw, + [CLKID_DSPA_0_DIV] = &t7_dspa_0_div.hw, + [CLKID_DSPA_0] = &t7_dspa_0.hw, + [CLKID_DSPA_1_SEL] = &t7_dspa_1_sel.hw, + [CLKID_DSPA_1_DIV] = &t7_dspa_1_div.hw, + [CLKID_DSPA_1] = &t7_dspa_1.hw, + [CLKID_DSPA] = &t7_dspa.hw, + [CLKID_DSPB_0_SEL] = &t7_dspb_0_sel.hw, + [CLKID_DSPB_0_DIV] = &t7_dspb_0_div.hw, + [CLKID_DSPB_0] = &t7_dspb_0.hw, + [CLKID_DSPB_1_SEL] = &t7_dspb_1_sel.hw, + [CLKID_DSPB_1_DIV] = &t7_dspb_1_div.hw, + [CLKID_DSPB_1] = &t7_dspb_1.hw, + [CLKID_DSPB] = &t7_dspb.hw, + [CLKID_24M] = &t7_24m.hw, + [CLKID_24M_DIV2] = &t7_24m_div2.hw, + [CLKID_12M] = &t7_12m.hw, + [CLKID_25M_DIV] = &t7_25m_div.hw, + [CLKID_25M] = &t7_25m.hw, + [CLKID_ANAKIN_0_SEL] = &t7_anakin_0_sel.hw, + [CLKID_ANAKIN_0_DIV] = &t7_anakin_0_div.hw, + [CLKID_ANAKIN_0] = &t7_anakin_0.hw, + [CLKID_ANAKIN_1_SEL] = &t7_anakin_1_sel.hw, + [CLKID_ANAKIN_1_DIV] = &t7_anakin_1_div.hw, + [CLKID_ANAKIN_1] = &t7_anakin_1.hw, + [CLKID_ANAKIN_01_SEL] = &t7_anakin_01_sel.hw, + [CLKID_ANAKIN] = &t7_anakin.hw, + [CLKID_MIPI_CSI_PHY_0_SEL] = &t7_mipi_csi_phy_0_sel.hw, + [CLKID_MIPI_CSI_PHY_0_DIV] = &t7_mipi_csi_phy_0_div.hw, + [CLKID_MIPI_CSI_PHY_0] = &t7_mipi_csi_phy_0.hw, + [CLKID_MIPI_CSI_PHY_1_SEL] = &t7_mipi_csi_phy_1_sel.hw, + [CLKID_MIPI_CSI_PHY_1_DIV] = &t7_mipi_csi_phy_1_div.hw, + [CLKID_MIPI_CSI_PHY_1] = &t7_mipi_csi_phy_1.hw, + [CLKID_MIPI_CSI_PHY] = &t7_mipi_csi_phy.hw, + [CLKID_MIPI_ISP_SEL] = &t7_mipi_isp_sel.hw, + [CLKID_MIPI_ISP_DIV] = &t7_mipi_isp_div.hw, + [CLKID_MIPI_ISP] = &t7_mipi_isp.hw, + [CLKID_TS_DIV] = &t7_ts_div.hw, + [CLKID_TS] = &t7_ts.hw, + [CLKID_MALI_0_SEL] = &t7_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &t7_mali_0_div.hw, + [CLKID_MALI_0] = &t7_mali_0.hw, + [CLKID_MALI_1_SEL] = &t7_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &t7_mali_1_div.hw, + [CLKID_MALI_1] = &t7_mali_1.hw, + [CLKID_MALI] = &t7_mali.hw, + [CLKID_ETH_RMII_SEL] = &t7_eth_rmii_sel.hw, + [CLKID_ETH_RMII_DIV] = &t7_eth_rmii_div.hw, + [CLKID_ETH_RMII] = &t7_eth_rmii.hw, + [CLKID_FCLK_DIV2_DIV8] = &t7_fdiv2_div8.hw, + [CLKID_ETH_125M] = &t7_eth_125m.hw, + [CLKID_SD_EMMC_A_SEL] = &t7_sd_emmc_a_sel.hw, + [CLKID_SD_EMMC_A_DIV] = &t7_sd_emmc_a_div.hw, + [CLKID_SD_EMMC_A] = &t7_sd_emmc_a.hw, + [CLKID_SD_EMMC_B_SEL] = &t7_sd_emmc_b_sel.hw, + [CLKID_SD_EMMC_B_DIV] = &t7_sd_emmc_b_div.hw, + [CLKID_SD_EMMC_B] = &t7_sd_emmc_b.hw, + [CLKID_SD_EMMC_C_SEL] = &t7_sd_emmc_c_sel.hw, + [CLKID_SD_EMMC_C_DIV] = &t7_sd_emmc_c_div.hw, + [CLKID_SD_EMMC_C] = &t7_sd_emmc_c.hw, + [CLKID_SPICC0_SEL] = &t7_spicc0_sel.hw, + [CLKID_SPICC0_DIV] = &t7_spicc0_div.hw, + [CLKID_SPICC0] = &t7_spicc0.hw, + [CLKID_SPICC1_SEL] = &t7_spicc1_sel.hw, + [CLKID_SPICC1_DIV] = &t7_spicc1_div.hw, + [CLKID_SPICC1] = &t7_spicc1.hw, + [CLKID_SPICC2_SEL] = &t7_spicc2_sel.hw, + [CLKID_SPICC2_DIV] = &t7_spicc2_div.hw, + [CLKID_SPICC2] = &t7_spicc2.hw, + [CLKID_SPICC3_SEL] = &t7_spicc3_sel.hw, + [CLKID_SPICC3_DIV] = &t7_spicc3_div.hw, + [CLKID_SPICC3] = &t7_spicc3.hw, + [CLKID_SPICC4_SEL] = &t7_spicc4_sel.hw, + [CLKID_SPICC4_DIV] = &t7_spicc4_div.hw, + [CLKID_SPICC4] = &t7_spicc4.hw, + [CLKID_SPICC5_SEL] = &t7_spicc5_sel.hw, + [CLKID_SPICC5_DIV] = &t7_spicc5_div.hw, + [CLKID_SPICC5] = &t7_spicc5.hw, + [CLKID_SARADC_SEL] = &t7_saradc_sel.hw, + [CLKID_SARADC_DIV] = &t7_saradc_div.hw, + [CLKID_SARADC] = &t7_saradc.hw, + [CLKID_PWM_A_SEL] = &t7_pwm_a_sel.hw, + [CLKID_PWM_A_DIV] = &t7_pwm_a_div.hw, + [CLKID_PWM_A] = &t7_pwm_a.hw, + [CLKID_PWM_B_SEL] = &t7_pwm_b_sel.hw, + [CLKID_PWM_B_DIV] = &t7_pwm_b_div.hw, + [CLKID_PWM_B] = &t7_pwm_b.hw, + [CLKID_PWM_C_SEL] = &t7_pwm_c_sel.hw, + [CLKID_PWM_C_DIV] = &t7_pwm_c_div.hw, + [CLKID_PWM_C] = &t7_pwm_c.hw, + [CLKID_PWM_D_SEL] = &t7_pwm_d_sel.hw, + [CLKID_PWM_D_DIV] = &t7_pwm_d_div.hw, + [CLKID_PWM_D] = &t7_pwm_d.hw, + [CLKID_PWM_E_SEL] = &t7_pwm_e_sel.hw, + [CLKID_PWM_E_DIV] = &t7_pwm_e_div.hw, + [CLKID_PWM_E] = &t7_pwm_e.hw, + [CLKID_PWM_F_SEL] = &t7_pwm_f_sel.hw, + [CLKID_PWM_F_DIV] = &t7_pwm_f_div.hw, + [CLKID_PWM_F] = &t7_pwm_f.hw, + [CLKID_PWM_AO_A_SEL] = &t7_pwm_ao_a_sel.hw, + [CLKID_PWM_AO_A_DIV] = &t7_pwm_ao_a_div.hw, + [CLKID_PWM_AO_A] = &t7_pwm_ao_a.hw, + [CLKID_PWM_AO_B_SEL] = &t7_pwm_ao_b_sel.hw, + [CLKID_PWM_AO_B_DIV] = &t7_pwm_ao_b_div.hw, + [CLKID_PWM_AO_B] = &t7_pwm_ao_b.hw, + [CLKID_PWM_AO_C_SEL] = &t7_pwm_ao_c_sel.hw, + [CLKID_PWM_AO_C_DIV] = &t7_pwm_ao_c_div.hw, + [CLKID_PWM_AO_C] = &t7_pwm_ao_c.hw, + [CLKID_PWM_AO_D_SEL] = &t7_pwm_ao_d_sel.hw, + [CLKID_PWM_AO_D_DIV] = &t7_pwm_ao_d_div.hw, + [CLKID_PWM_AO_D] = &t7_pwm_ao_d.hw, + [CLKID_PWM_AO_E_SEL] = &t7_pwm_ao_e_sel.hw, + [CLKID_PWM_AO_E_DIV] = &t7_pwm_ao_e_div.hw, + [CLKID_PWM_AO_E] = &t7_pwm_ao_e.hw, + [CLKID_PWM_AO_F_SEL] = &t7_pwm_ao_f_sel.hw, + [CLKID_PWM_AO_F_DIV] = &t7_pwm_ao_f_div.hw, + [CLKID_PWM_AO_F] = &t7_pwm_ao_f.hw, + [CLKID_PWM_AO_G_SEL] = &t7_pwm_ao_g_sel.hw, + [CLKID_PWM_AO_G_DIV] = &t7_pwm_ao_g_div.hw, + [CLKID_PWM_AO_G] = &t7_pwm_ao_g.hw, + [CLKID_PWM_AO_H_SEL] = &t7_pwm_ao_h_sel.hw, + [CLKID_PWM_AO_H_DIV] = &t7_pwm_ao_h_div.hw, + [CLKID_PWM_AO_H] = &t7_pwm_ao_h.hw, + [CLKID_SYS_DDR] = &t7_sys_ddr.hw, + [CLKID_SYS_DOS] = &t7_sys_dos.hw, + [CLKID_SYS_MIPI_DSI_A] = &t7_sys_mipi_dsi_a.hw, + [CLKID_SYS_MIPI_DSI_B] = &t7_sys_mipi_dsi_b.hw, + [CLKID_SYS_ETHPHY] = &t7_sys_ethphy.hw, + [CLKID_SYS_MALI] = &t7_sys_mali.hw, + [CLKID_SYS_AOCPU] = &t7_sys_aocpu.hw, + [CLKID_SYS_AUCPU] = &t7_sys_aucpu.hw, + [CLKID_SYS_CEC] = &t7_sys_cec.hw, + [CLKID_SYS_GDC] = &t7_sys_gdc.hw, + [CLKID_SYS_DESWARP] = &t7_sys_deswarp.hw, + [CLKID_SYS_AMPIPE_NAND] = &t7_sys_ampipe_nand.hw, + [CLKID_SYS_AMPIPE_ETH] = &t7_sys_ampipe_eth.hw, + [CLKID_SYS_AM2AXI0] = &t7_sys_am2axi0.hw, + [CLKID_SYS_AM2AXI1] = &t7_sys_am2axi1.hw, + [CLKID_SYS_AM2AXI2] = &t7_sys_am2axi2.hw, + [CLKID_SYS_SD_EMMC_A] = &t7_sys_sd_emmc_a.hw, + [CLKID_SYS_SD_EMMC_B] = &t7_sys_sd_emmc_b.hw, + [CLKID_SYS_SD_EMMC_C] = &t7_sys_sd_emmc_c.hw, + [CLKID_SYS_SMARTCARD] = &t7_sys_smartcard.hw, + [CLKID_SYS_ACODEC] = &t7_sys_acodec.hw, + [CLKID_SYS_SPIFC] = &t7_sys_spifc.hw, + [CLKID_SYS_MSR_CLK] = &t7_sys_msr_clk.hw, + [CLKID_SYS_IR_CTRL] = &t7_sys_ir_ctrl.hw, + [CLKID_SYS_AUDIO] = &t7_sys_audio.hw, + [CLKID_SYS_ETH] = &t7_sys_eth.hw, + [CLKID_SYS_UART_A] = &t7_sys_uart_a.hw, + [CLKID_SYS_UART_B] = &t7_sys_uart_b.hw, + [CLKID_SYS_UART_C] = &t7_sys_uart_c.hw, + [CLKID_SYS_UART_D] = &t7_sys_uart_d.hw, + [CLKID_SYS_UART_E] = &t7_sys_uart_e.hw, + [CLKID_SYS_UART_F] = &t7_sys_uart_f.hw, + [CLKID_SYS_AIFIFO] = &t7_sys_aififo.hw, + [CLKID_SYS_SPICC2] = &t7_sys_spicc2.hw, + [CLKID_SYS_SPICC3] = &t7_sys_spicc3.hw, + [CLKID_SYS_SPICC4] = &t7_sys_spicc4.hw, + [CLKID_SYS_TS_A73] = &t7_sys_ts_a73.hw, + [CLKID_SYS_TS_A53] = &t7_sys_ts_a53.hw, + [CLKID_SYS_SPICC5] = &t7_sys_spicc5.hw, + [CLKID_SYS_G2D] = &t7_sys_g2d.hw, + [CLKID_SYS_SPICC0] = &t7_sys_spicc0.hw, + [CLKID_SYS_SPICC1] = &t7_sys_spicc1.hw, + [CLKID_SYS_PCIE] = &t7_sys_pcie.hw, + [CLKID_SYS_USB] = &t7_sys_usb.hw, + [CLKID_SYS_PCIE_PHY] = &t7_sys_pcie_phy.hw, + [CLKID_SYS_I2C_AO_A] = &t7_sys_i2c_ao_a.hw, + [CLKID_SYS_I2C_AO_B] = &t7_sys_i2c_ao_b.hw, + [CLKID_SYS_I2C_M_A] = &t7_sys_i2c_m_a.hw, + [CLKID_SYS_I2C_M_B] = &t7_sys_i2c_m_b.hw, + [CLKID_SYS_I2C_M_C] = &t7_sys_i2c_m_c.hw, + [CLKID_SYS_I2C_M_D] = &t7_sys_i2c_m_d.hw, + [CLKID_SYS_I2C_M_E] = &t7_sys_i2c_m_e.hw, + [CLKID_SYS_I2C_M_F] = &t7_sys_i2c_m_f.hw, + [CLKID_SYS_HDMITX_APB] = &t7_sys_hdmitx_apb.hw, + [CLKID_SYS_I2C_S_A] = &t7_sys_i2c_s_a.hw, + [CLKID_SYS_HDMIRX_PCLK] = &t7_sys_hdmirx_pclk.hw, + [CLKID_SYS_MMC_APB] = &t7_sys_mmc_apb.hw, + [CLKID_SYS_MIPI_ISP_PCLK] = &t7_sys_mipi_isp_pclk.hw, + [CLKID_SYS_RSA] = &t7_sys_rsa.hw, + [CLKID_SYS_PCLK_SYS_APB] = &t7_sys_pclk_sys_apb.hw, + [CLKID_SYS_A73PCLK_APB] = &t7_sys_a73pclk_apb.hw, + [CLKID_SYS_DSPA] = &t7_sys_dspa.hw, + [CLKID_SYS_DSPB] = &t7_sys_dspb.hw, + [CLKID_SYS_VPU_INTR] = &t7_sys_vpu_intr.hw, + [CLKID_SYS_SAR_ADC] = &t7_sys_sar_adc.hw, + [CLKID_SYS_GIC] = &t7_sys_gic.hw, + [CLKID_SYS_TS_GPU] = &t7_sys_ts_gpu.hw, + [CLKID_SYS_TS_NNA] = &t7_sys_ts_nna.hw, + [CLKID_SYS_TS_VPU] = &t7_sys_ts_vpu.hw, + [CLKID_SYS_TS_HEVC] = &t7_sys_ts_hevc.hw, + [CLKID_SYS_PWM_AO_AB] = &t7_sys_pwm_ao_ab.hw, + [CLKID_SYS_PWM_AO_CD] = &t7_sys_pwm_ao_cd.hw, + [CLKID_SYS_PWM_AO_EF] = &t7_sys_pwm_ao_ef.hw, + [CLKID_SYS_PWM_AO_GH] = &t7_sys_pwm_ao_gh.hw, + [CLKID_SYS_PWM_AB] = &t7_sys_pwm_ab.hw, + [CLKID_SYS_PWM_CD] = &t7_sys_pwm_cd.hw, + [CLKID_SYS_PWM_EF] = &t7_sys_pwm_ef.hw, +}; + +static const struct meson_clkc_data t7_peripherals_data = { + .hw_clks = { + .hws = t7_peripherals_hw_clks, + .num = ARRAY_SIZE(t7_peripherals_hw_clks), + }, +}; + +static const struct of_device_id t7_peripherals_clkc_match_table[] = { + { + .compatible = "amlogic,t7-peripherals-clkc", + .data = &t7_peripherals_data + }, + {} +}; +MODULE_DEVICE_TABLE(of, t7_peripherals_clkc_match_table); + +static struct platform_driver t7_peripherals_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "t7-peripherals-clkc", + .of_match_table = t7_peripherals_clkc_match_table, + }, +}; +module_platform_driver(t7_peripherals_clkc_driver); + +MODULE_DESCRIPTION("Amlogic T7 Peripherals Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/t7-pll.c b/drivers/clk/meson/t7-pll.c new file mode 100644 index 000000000..0a622f45f --- /dev/null +++ b/drivers/clk/meson/t7-pll.c @@ -0,0 +1,1074 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved. + * Author: Jian Hu + */ + +#include +#include +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" +#include "meson-clkc-utils.h" +#include + +#define GP0PLL_CTRL0 0x00 +#define GP0PLL_CTRL1 0x04 +#define GP0PLL_CTRL2 0x08 +#define GP0PLL_CTRL3 0x0c +#define GP0PLL_CTRL4 0x10 +#define GP0PLL_CTRL5 0x14 +#define GP0PLL_CTRL6 0x18 +#define GP0PLL_STS 0x1c + +#define GP1PLL_CTRL0 0x00 +#define GP1PLL_CTRL1 0x04 +#define GP1PLL_CTRL2 0x08 +#define GP1PLL_CTRL3 0x0c +#define GP1PLL_STS 0x1c + +#define HIFIPLL_CTRL0 0x00 +#define HIFIPLL_CTRL1 0x04 +#define HIFIPLL_CTRL2 0x08 +#define HIFIPLL_CTRL3 0x0c +#define HIFIPLL_CTRL4 0x10 +#define HIFIPLL_CTRL5 0x14 +#define HIFIPLL_CTRL6 0x18 +#define HIFIPLL_STS 0x1c + +#define PCIEPLL_CTRL0 0x00 +#define PCIEPLL_CTRL1 0x04 +#define PCIEPLL_CTRL2 0x08 +#define PCIEPLL_CTRL3 0x0c +#define PCIEPLL_CTRL4 0x10 +#define PCIEPLL_CTRL5 0x14 +#define PCIEPLL_STS 0x18 + +#define MPLL_CTRL0 0x00 +#define MPLL_CTRL1 0x04 +#define MPLL_CTRL2 0x08 +#define MPLL_CTRL3 0x0c +#define MPLL_CTRL4 0x10 +#define MPLL_CTRL5 0x14 +#define MPLL_CTRL6 0x18 +#define MPLL_CTRL7 0x1c +#define MPLL_CTRL8 0x20 +#define MPLL_STS 0x24 + +#define HDMIPLL_CTRL0 0x00 +#define HDMIPLL_CTRL1 0x04 +#define HDMIPLL_CTRL2 0x08 +#define HDMIPLL_CTRL3 0x0c +#define HDMIPLL_CTRL4 0x10 +#define HDMIPLL_CTRL5 0x14 +#define HDMIPLL_CTRL6 0x18 +#define HDMIPLL_STS 0x1c + +#define MCLK_PLL_CNTL0 0x00 +#define MCLK_PLL_CNTL1 0x04 +#define MCLK_PLL_CNTL2 0x08 +#define MCLK_PLL_CNTL3 0x0c +#define MCLK_PLL_CNTL4 0x10 +#define MCLK_PLL_STS 0x14 + +static const struct pll_mult_range t7_media_pll_mult_range = { + .min = 125, + .max = 250, +}; + +static const struct reg_sequence t7_gp0_init_regs[] = { + { .reg = GP0PLL_CTRL1, .def = 0x00000000 }, + { .reg = GP0PLL_CTRL2, .def = 0x00000000 }, + { .reg = GP0PLL_CTRL3, .def = 0x48681c00 }, + { .reg = GP0PLL_CTRL4, .def = 0x88770290 }, + { .reg = GP0PLL_CTRL5, .def = 0x3927200a }, + { .reg = GP0PLL_CTRL6, .def = 0x56540000 }, +}; + +static struct clk_regmap t7_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = GP0PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = GP0PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = GP0PLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = GP0PLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = GP0PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_gp0_init_regs, + .init_count = ARRAY_SIZE(t7_gp0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = GP0PLL_CTRL0, + .shift = 16, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data) { + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Compared with GP0 PLL, GP1 PLL is a newly designed PLL with + * a DCO range of 1.6GHz to 3.2GHz. + */ +static const struct pll_mult_range t7_gp1_pll_mult_range = { + .min = 67, + .max = 133, +}; + +static const struct reg_sequence t7_gp1_init_regs[] = { + { .reg = GP1PLL_CTRL1, .def = 0x1420500f }, + { .reg = GP1PLL_CTRL2, .def = 0x00023001 }, + { .reg = GP1PLL_CTRL3, .def = 0x00000000 }, +}; + +static struct clk_regmap t7_gp1_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = GP1PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = GP1PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = GP1PLL_CTRL0, + .shift = 16, + .width = 5, + }, + .l = { + .reg_off = GP1PLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = GP1PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_gp1_pll_mult_range, + .init_regs = t7_gp1_init_regs, + .init_count = ARRAY_SIZE(t7_gp1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp1_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_gp1_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = GP1PLL_CTRL0, + .shift = 12, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data) { + .name = "gp1_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_gp1_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_hifi_init_regs[] = { + { .reg = HIFIPLL_CTRL1, .def = 0x00000000 }, + { .reg = HIFIPLL_CTRL2, .def = 0x00000000 }, + { .reg = HIFIPLL_CTRL3, .def = 0x6a285c00 }, + { .reg = HIFIPLL_CTRL4, .def = 0x65771290 }, + { .reg = HIFIPLL_CTRL5, .def = 0x3927200a }, + { .reg = HIFIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap t7_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HIFIPLL_CTRL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HIFIPLL_STS, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HIFIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_hifi_init_regs, + .init_count = ARRAY_SIZE(t7_hifi_init_regs), + .frac_max = 100000, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HIFIPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data) { + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The T7 PCIE PLL is fined tuned to deliver a very precise + * 100MHz reference clock for the PCIe Analog PHY, and thus requires + * a strict register sequence to enable the PLL. + */ +static const struct reg_sequence t7_pcie_pll_init_regs[] = { + { .reg = PCIEPLL_CTRL0, .def = 0x200c04c8 }, + { .reg = PCIEPLL_CTRL0, .def = 0x300c04c8 }, + { .reg = PCIEPLL_CTRL1, .def = 0x30000000 }, + { .reg = PCIEPLL_CTRL2, .def = 0x00001100 }, + { .reg = PCIEPLL_CTRL3, .def = 0x10058e00 }, + { .reg = PCIEPLL_CTRL4, .def = 0x000100c0 }, + { .reg = PCIEPLL_CTRL5, .def = 0x68000048 }, + { .reg = PCIEPLL_CTRL5, .def = 0x68000068, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL4, .def = 0x008100c0, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL0, .def = 0x340c04c8 }, + { .reg = PCIEPLL_CTRL0, .def = 0x140c04c8, .delay_us = 20 }, + { .reg = PCIEPLL_CTRL2, .def = 0x00001000 } +}; + +static struct clk_regmap t7_pcie_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = PCIEPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = PCIEPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = PCIEPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = PCIEPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = PCIEPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .init_regs = t7_pcie_pll_init_regs, + .init_count = ARRAY_SIZE(t7_pcie_pll_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco", + .ops = &meson_clk_pcie_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor t7_pcie_pll_dco_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_dco_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = PCIEPLL_CTRL0, + .shift = 16, + .width = 5, + /* the divisor is 32 when [16:21] = 0 */ + .flags = CLK_DIVIDER_MAX_AT_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_dco_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_pcie_pll = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_pcie_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor t7_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +static const struct reg_sequence t7_mpll0_init_regs[] = { + { .reg = MPLL_CTRL2, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL1, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll0_init_regs, + .init_count = ARRAY_SIZE(t7_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll1_init_regs[] = { + { .reg = MPLL_CTRL4, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL3, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll1_init_regs, + .init_count = ARRAY_SIZE(t7_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll2_init_regs[] = { + { .reg = MPLL_CTRL6, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL5, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll2_init_regs, + .init_count = ARRAY_SIZE(t7_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_mpll3_init_regs[] = { + { .reg = MPLL_CTRL8, .def = 0x40000033 } +}; + +static struct clk_regmap t7_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = MPLL_CTRL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = MPLL_CTRL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = MPLL_CTRL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = MPLL_CTRL7, + .shift = 29, + .width = 1, + }, + .init_regs = t7_mpll3_init_regs, + .init_count = ARRAY_SIZE(t7_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MPLL_CTRL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence t7_hdmi_init_regs[] = { + { .reg = HDMIPLL_CTRL1, .def = 0x00000000 }, + { .reg = HDMIPLL_CTRL2, .def = 0x00000000 }, + { .reg = HDMIPLL_CTRL3, .def = 0x6a28dc00 }, + { .reg = HDMIPLL_CTRL4, .def = 0x65771290 }, + { .reg = HDMIPLL_CTRL5, .def = 0x39272000 }, + { .reg = HDMIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap t7_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HDMIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HDMIPLL_CTRL0, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HDMIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = HDMIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HDMIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &t7_media_pll_mult_range, + .init_regs = t7_hdmi_init_regs, + .init_count = ARRAY_SIZE(t7_hdmi_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "in0", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap t7_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HDMIPLL_CTRL0, + .shift = 16, + .width = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HDMIPLL_CTRL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_mult_range t7_mclk_pll_mult_range = { + .min = 67, + .max = 133, +}; + +static const struct reg_sequence t7_mclk_init_regs[] = { + { .reg = MCLK_PLL_CNTL1, .def = 0x1470500f }, + { .reg = MCLK_PLL_CNTL2, .def = 0x00023001 }, + { .reg = MCLK_PLL_CNTL3, .def = 0x18180000 }, + { .reg = MCLK_PLL_CNTL4, .def = 0x00180303 }, +}; + +static struct clk_regmap t7_mclk_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 16, + .width = 5, + }, + .l = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = MCLK_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .l_detect = { + .reg_off = MCLK_PLL_CNTL2, + .shift = 6, + .width = 1, + }, + .range = &t7_mclk_pll_mult_range, + .init_regs = t7_mclk_init_regs, + .init_count = ARRAY_SIZE(t7_mclk_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "in0", + }, + .num_parents = 1, + }, +}; + +/* max div is 16 */ +static const struct clk_div_table t7_mclk_div[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { .val = 4, .div = 16 }, + { /* sentinel */ } +}; + +static struct clk_regmap t7_mclk_pre_od = { + .data = &(struct clk_regmap_div_data){ + .offset = MCLK_PLL_CNTL0, + .shift = 12, + .width = 3, + .table = t7_mclk_div, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pre_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = MCLK_PLL_CNTL4, + .shift = 16, + .width = 5, + .flags = CLK_DIVIDER_ONE_BASED, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_pre_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = MCLK_PLL_CNTL4, + .mask = 0x3, + .shift = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &t7_mclk_pll.hw }, + { .fw_name = "in1", }, + { .fw_name = "in2", }, + }, + .num_parents = 3, + }, +}; + +static struct clk_fixed_factor t7_mclk_0_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mclk_0_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mclk_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_0_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_0_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_0_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = MCLK_PLL_CNTL4, + .mask = 0x3, + .shift = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "mclk_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &t7_mclk_pll.hw }, + { .fw_name = "in1", }, + { .fw_name = "in2", }, + }, + .num_parents = 3, + }, +}; + +static struct clk_fixed_factor t7_mclk_1_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mclk_1_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &t7_mclk_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_1_pre", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_1_div2.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap t7_mclk_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = MCLK_PLL_CNTL4, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mclk_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &t7_mclk_1_pre.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_hw *t7_gp0_hw_clks[] = { + [CLKID_GP0_PLL_DCO] = &t7_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &t7_gp0_pll.hw, +}; + +static struct clk_hw *t7_gp1_hw_clks[] = { + [CLKID_GP1_PLL_DCO] = &t7_gp1_pll_dco.hw, + [CLKID_GP1_PLL] = &t7_gp1_pll.hw, +}; + +static struct clk_hw *t7_hifi_hw_clks[] = { + [CLKID_HIFI_PLL_DCO] = &t7_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &t7_hifi_pll.hw, +}; + +static struct clk_hw *t7_pcie_hw_clks[] = { + [CLKID_PCIE_PLL_DCO] = &t7_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_DCO_DIV2] = &t7_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &t7_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &t7_pcie_pll.hw, +}; + +static struct clk_hw *t7_mpll_hw_clks[] = { + [CLKID_MPLL_PREDIV] = &t7_mpll_prediv.hw, + [CLKID_MPLL0_DIV] = &t7_mpll0_div.hw, + [CLKID_MPLL0] = &t7_mpll0.hw, + [CLKID_MPLL1_DIV] = &t7_mpll1_div.hw, + [CLKID_MPLL1] = &t7_mpll1.hw, + [CLKID_MPLL2_DIV] = &t7_mpll2_div.hw, + [CLKID_MPLL2] = &t7_mpll2.hw, + [CLKID_MPLL3_DIV] = &t7_mpll3_div.hw, + [CLKID_MPLL3] = &t7_mpll3.hw, +}; + +static struct clk_hw *t7_hdmi_hw_clks[] = { + [CLKID_HDMI_PLL_DCO] = &t7_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &t7_hdmi_pll_od.hw, + [CLKID_HDMI_PLL] = &t7_hdmi_pll.hw, +}; + +static struct clk_hw *t7_mclk_hw_clks[] = { + [CLKID_MCLK_PLL_DCO] = &t7_mclk_pll_dco.hw, + [CLKID_MCLK_PRE] = &t7_mclk_pre_od.hw, + [CLKID_MCLK_PLL] = &t7_mclk_pll.hw, + [CLKID_MCLK_0_SEL] = &t7_mclk_0_sel.hw, + [CLKID_MCLK_0_DIV2] = &t7_mclk_0_div2.hw, + [CLKID_MCLK_0_PRE] = &t7_mclk_0_pre.hw, + [CLKID_MCLK_0] = &t7_mclk_0.hw, + [CLKID_MCLK_1_SEL] = &t7_mclk_1_sel.hw, + [CLKID_MCLK_1_DIV2] = &t7_mclk_1_div2.hw, + [CLKID_MCLK_1_PRE] = &t7_mclk_1_pre.hw, + [CLKID_MCLK_1] = &t7_mclk_1.hw, +}; + +static const struct meson_clkc_data t7_gp0_data = { + .hw_clks = { + .hws = t7_gp0_hw_clks, + .num = ARRAY_SIZE(t7_gp0_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_gp1_data = { + .hw_clks = { + .hws = t7_gp1_hw_clks, + .num = ARRAY_SIZE(t7_gp1_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_hifi_data = { + .hw_clks = { + .hws = t7_hifi_hw_clks, + .num = ARRAY_SIZE(t7_hifi_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_pcie_data = { + .hw_clks = { + .hws = t7_pcie_hw_clks, + .num = ARRAY_SIZE(t7_pcie_hw_clks), + }, +}; + +static const struct reg_sequence t7_mpll_init_regs[] = { + { .reg = MPLL_CTRL0, .def = 0x00000543 } +}; + +static const struct meson_clkc_data t7_mpll_data = { + .hw_clks = { + .hws = t7_mpll_hw_clks, + .num = ARRAY_SIZE(t7_mpll_hw_clks), + }, + .init_regs = t7_mpll_init_regs, + .init_count = ARRAY_SIZE(t7_mpll_init_regs), +}; + +static const struct meson_clkc_data t7_hdmi_data = { + .hw_clks = { + .hws = t7_hdmi_hw_clks, + .num = ARRAY_SIZE(t7_hdmi_hw_clks), + }, +}; + +static const struct meson_clkc_data t7_mclk_data = { + .hw_clks = { + .hws = t7_mclk_hw_clks, + .num = ARRAY_SIZE(t7_mclk_hw_clks), + }, +}; + +static const struct of_device_id t7_pll_clkc_match_table[] = { + { .compatible = "amlogic,t7-gp0-pll", .data = &t7_gp0_data, }, + { .compatible = "amlogic,t7-gp1-pll", .data = &t7_gp1_data, }, + { .compatible = "amlogic,t7-hifi-pll", .data = &t7_hifi_data, }, + { .compatible = "amlogic,t7-pcie-pll", .data = &t7_pcie_data, }, + { .compatible = "amlogic,t7-mpll", .data = &t7_mpll_data, }, + { .compatible = "amlogic,t7-hdmi-pll", .data = &t7_hdmi_data, }, + { .compatible = "amlogic,t7-mclk-pll", .data = &t7_mclk_data, }, + {} +}; +MODULE_DEVICE_TABLE(of, t7_pll_clkc_match_table); + +static struct platform_driver t7_pll_clkc_driver = { + .probe = meson_clkc_mmio_probe, + .driver = { + .name = "t7-pll-clkc", + .of_match_table = t7_pll_clkc_match_table, + }, +}; +module_platform_driver(t7_pll_clkc_driver); + +MODULE_DESCRIPTION("Amlogic T7 PLL Clock Controller driver"); +MODULE_AUTHOR("Jian Hu "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c new file mode 100644 index 000000000..009bd1193 --- /dev/null +++ b/drivers/clk/meson/vclk.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Neil Armstrong + */ + +#include +#include "vclk.h" + +/* The VCLK gate has a supplementary reset bit to pulse after ungating */ + +static inline struct meson_vclk_gate_data * +clk_get_meson_vclk_gate_data(struct clk_regmap *clk) +{ + return (struct meson_vclk_gate_data *)clk->data; +} + +static int meson_vclk_gate_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk); + + meson_parm_write(clk->map, &vclk->enable, 1); + + /* Do a reset pulse */ + meson_parm_write(clk->map, &vclk->reset, 1); + meson_parm_write(clk->map, &vclk->reset, 0); + + return 0; +} + +static void meson_vclk_gate_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk); + + meson_parm_write(clk->map, &vclk->enable, 0); +} + +static int meson_vclk_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk); + + return meson_parm_read(clk->map, &vclk->enable); +} + +const struct clk_ops meson_vclk_gate_ops = { + .init = clk_regmap_init, + .enable = meson_vclk_gate_enable, + .disable = meson_vclk_gate_disable, + .is_enabled = meson_vclk_gate_is_enabled, +}; +EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, "CLK_MESON"); + +/* The VCLK Divider has supplementary reset & enable bits */ + +static inline struct meson_vclk_div_data * +clk_get_meson_vclk_div_data(struct clk_regmap *clk) +{ + return (struct meson_vclk_div_data *)clk->data; +} + +static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + + return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div), + vclk->table, vclk->flags, vclk->div.width); +} + +static int meson_vclk_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + + return divider_determine_rate(hw, req, vclk->table, vclk->div.width, + vclk->flags); +} + +static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + int ret; + + ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width, + vclk->flags); + if (ret < 0) + return ret; + + meson_parm_write(clk->map, &vclk->div, ret); + + return 0; +}; + +static int meson_vclk_div_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + + /* Unreset the divider when ungating */ + meson_parm_write(clk->map, &vclk->reset, 0); + meson_parm_write(clk->map, &vclk->enable, 1); + + return 0; +} + +static void meson_vclk_div_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + + /* Reset the divider when gating */ + meson_parm_write(clk->map, &vclk->enable, 0); + meson_parm_write(clk->map, &vclk->reset, 1); +} + +static int meson_vclk_div_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk); + + return meson_parm_read(clk->map, &vclk->enable); +} + +const struct clk_ops meson_vclk_div_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_vclk_div_recalc_rate, + .determine_rate = meson_vclk_div_determine_rate, + .set_rate = meson_vclk_div_set_rate, + .enable = meson_vclk_div_enable, + .disable = meson_vclk_div_disable, + .is_enabled = meson_vclk_div_is_enabled, +}; +EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic vclk clock driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/vclk.h b/drivers/clk/meson/vclk.h new file mode 100644 index 000000000..20b0b181d --- /dev/null +++ b/drivers/clk/meson/vclk.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Neil Armstrong + */ + +#ifndef __VCLK_H +#define __VCLK_H + +#include "clk-regmap.h" +#include "parm.h" + +/** + * struct meson_vclk_gate_data - vclk_gate regmap backed specific data + * + * @enable: vclk enable field + * @reset: vclk reset field + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored + */ +struct meson_vclk_gate_data { + struct parm enable; + struct parm reset; + u8 flags; +}; + +extern const struct clk_ops meson_vclk_gate_ops; + +/** + * struct meson_vclk_div_data - vclk_div regmap back specific data + * + * @div: divider field + * @enable: vclk divider enable field + * @reset: vclk divider reset field + * @table: array of value/divider pairs, last entry should have div = 0 + * + * Flags: + * Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored + */ +struct meson_vclk_div_data { + struct parm div; + struct parm enable; + struct parm reset; + const struct clk_div_table *table; + u8 flags; +}; + +extern const struct clk_ops meson_vclk_div_ops; + +#endif /* __VCLK_H */ diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c new file mode 100644 index 000000000..2a3cdbe6d --- /dev/null +++ b/drivers/clk/meson/vid-pll-div.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Neil Armstrong + */ + +#include +#include + +#include "clk-regmap.h" +#include "vid-pll-div.h" + +static inline struct meson_vid_pll_div_data * +meson_vid_pll_div_data(struct clk_regmap *clk) +{ + return (struct meson_vid_pll_div_data *)clk->data; +} + +/* + * This vid_pll divided is a fully programmable fractionnal divider to + * achieve complex video clock rates. + * + * Here are provided the commonly used fraction values provided by Amlogic. + */ + +struct vid_pll_div { + unsigned int shift_val; + unsigned int shift_sel; + unsigned int divider; + unsigned int multiplier; +}; + +#define VID_PLL_DIV(_val, _sel, _ft, _fb) \ + { \ + .shift_val = (_val), \ + .shift_sel = (_sel), \ + .divider = (_ft), \ + .multiplier = (_fb), \ + } + +static const struct vid_pll_div vid_pll_div_table[] = { + VID_PLL_DIV(0x0aaa, 0, 2, 1), /* 2/1 => /2 */ + VID_PLL_DIV(0x5294, 2, 5, 2), /* 5/2 => /2.5 */ + VID_PLL_DIV(0x0db6, 0, 3, 1), /* 3/1 => /3 */ + VID_PLL_DIV(0x36cc, 1, 7, 2), /* 7/2 => /3.5 */ + VID_PLL_DIV(0x6666, 2, 15, 4), /* 15/4 => /3.75 */ + VID_PLL_DIV(0x0ccc, 0, 4, 1), /* 4/1 => /4 */ + VID_PLL_DIV(0x739c, 2, 5, 1), /* 5/1 => /5 */ + VID_PLL_DIV(0x0e38, 0, 6, 1), /* 6/1 => /6 */ + VID_PLL_DIV(0x0000, 3, 25, 4), /* 25/4 => /6.25 */ + VID_PLL_DIV(0x3c78, 1, 7, 1), /* 7/1 => /7 */ + VID_PLL_DIV(0x78f0, 2, 15, 2), /* 15/2 => /7.5 */ + VID_PLL_DIV(0x0fc0, 0, 12, 1), /* 12/1 => /12 */ + VID_PLL_DIV(0x3f80, 1, 14, 1), /* 14/1 => /14 */ + VID_PLL_DIV(0x7f80, 2, 15, 1), /* 15/1 => /15 */ +}; + +#define to_meson_vid_pll_div(_hw) \ + container_of(_hw, struct meson_vid_pll_div, hw) + +static const struct vid_pll_div *_get_table_val(unsigned int shift_val, + unsigned int shift_sel) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) { + if (vid_pll_div_table[i].shift_val == shift_val && + vid_pll_div_table[i].shift_sel == shift_sel) + return &vid_pll_div_table[i]; + } + + return NULL; +} + +static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk); + const struct vid_pll_div *div; + + div = _get_table_val(meson_parm_read(clk->map, &pll_div->val), + meson_parm_read(clk->map, &pll_div->sel)); + if (!div || !div->divider) { + pr_debug("%s: Invalid config value for vid_pll_div\n", __func__); + return 0; + } + + return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider); +} + +const struct clk_ops meson_vid_pll_div_ro_ops = { + .init = clk_regmap_init, + .recalc_rate = meson_vid_pll_div_recalc_rate, +}; +EXPORT_SYMBOL_NS_GPL(meson_vid_pll_div_ro_ops, "CLK_MESON"); + +MODULE_DESCRIPTION("Amlogic video pll divider driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h new file mode 100644 index 000000000..c0128e33c --- /dev/null +++ b/drivers/clk/meson/vid-pll-div.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_VID_PLL_DIV_H +#define __MESON_VID_PLL_DIV_H + +#include +#include "parm.h" + +struct meson_vid_pll_div_data { + struct parm val; + struct parm sel; +}; + +extern const struct clk_ops meson_vid_pll_div_ro_ops; + +#endif /* __MESON_VID_PLL_DIV_H */ -- cgit v1.3.1