From 034dd340b08be1f2f0477ad16131d609f9dbd53c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 30 Aug 2026 09:22:00 -0700 Subject: Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing fixes from Steven Rostedt: - Fix error output of boot instance creation failure Currently if a boot instance creation fails, instead of printing out the name of the instance that failed, it prints "(null)". That is because it prints "cur_str" that had already been processed by strsep(). Print the saved name instead. While at it, print the error code of the failure. - Fix use-after-free for same named historgrams Histograms can be named so that they can be used in multiple events. But if the named histogram has a variable attached, the second event that uses the named histogram which duplicates it and needs to free the original after duplication leaves the old variable in place and still visible. If another histogram uses than variable, it will use the stale one which will try to reference the freed duplicate histogram and crash the kernel. Free the duplicate variables along with the duplicated histogram data. - Check return value of kthread_run() in event self test The events self tests uses a kthread for testing but does not check if it succeeded in creating a kthread. If the kthread creation were to fail, the code will still try to call kthread_stop() on the error returned. - Fix race between reading trace_pipe and updating subbuffer size If a user is reading the trace_pipe file at the same time they update the ring buffer sub-buffer size, can cause the trace_pipe read to read stale data. Add trace_access_lock() around updating the ring buffer sub-buffer size. - Fix eventfs_inode on failure path in creation of the events directory In the creation of the "events" directory, if after allocating the eventfs_inode a failure is detected, it calls cleanup_ei() which calls free_ei(). The free_ei() will test if eventfs_inode being freed has no children. It is a bug if it does. But on the failure case of the creation of the "events" directory, the children lists have not yet been initialized and the free will trigger a warning because list_empty() on an uninitialized list returns false. Move the initialization into init_ei() where it makes more sense and makes sure that a created eventfs_inode has its lists initialized upon creation. - Check return value of kthread_run() in ftrace direct sample code The sample code that shows how to use the ftrace direct calls does not test the return of kthread_run() to see if it succeeds. Return a failure if the kthread_run() doesn't succeed. - Clear user events state on fork in case of alloc failure On fork, the child gets a pointer to the parent's user events state. It makes a copy of it then updates the child's pointer to it. But if the allocation fails, the duplication function leaves the child with a pointer to its parent's descriptor. When the child cleans up its data, it will free the parent's descriptor while the parent is still using it. In the duplication function, set the child's user_event_mm to NULL before testing if the allocation succeeded, and when it exits it will not free the parent's descriptor. - Fix retry exhaustion in simple ring buffer reader swap simple_ring_buffer_swap_reader_page() starts with retry set to 8 and post-decrements it only after a failed link replacement. On the final attempt, a successful replacement leaves retry at zero, while a failed replacement leaves it at -1. But the check for success expects the retry value to be non-zero and exits with an error on zero. This is the opposite result. Fix it. - Fail nicely when the remote swap_reader_page() returns an error Currently, if the swap_reader_page() of a remote buffer fails, it triggers a WARN_ON_ONCE() and continues normally. Instead, have it exit with an error and a pr_warn() print instead of a full WARNING. * tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ring-buffer: Stop remote reader update when page swap fails tracing: Fix retry exhaustion in simple ring buffer reader swap tracing/user_events: Clear copied tracing state before fork duplication samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify eventfs: Initialize ei->children and ei->list in init_ei() tracing: Fix use-after-free in trace_pipe read on sub-buffer order change tracing: Fix crash passing ERR_PTR to kthread_stop() tracing: Fix use-after-free with same-name named triggers tracing: Fix logged instance name on creation failure --- drivers/clk/starfive/Kconfig | 74 ++++ drivers/clk/starfive/Makefile | 12 + drivers/clk/starfive/clk-starfive-jh7100-audio.c | 158 +++++++ drivers/clk/starfive/clk-starfive-jh7100.c | 368 ++++++++++++++++ drivers/clk/starfive/clk-starfive-jh7110-aon.c | 144 ++++++ drivers/clk/starfive/clk-starfive-jh7110-isp.c | 220 +++++++++ drivers/clk/starfive/clk-starfive-jh7110-pll.c | 507 +++++++++++++++++++++ drivers/clk/starfive/clk-starfive-jh7110-stg.c | 163 +++++++ drivers/clk/starfive/clk-starfive-jh7110-sys.c | 538 +++++++++++++++++++++++ drivers/clk/starfive/clk-starfive-jh7110-vout.c | 227 ++++++++++ drivers/clk/starfive/clk-starfive-jh7110.h | 17 + drivers/clk/starfive/clk-starfive-jh71x0.c | 339 ++++++++++++++ drivers/clk/starfive/clk-starfive-jh71x0.h | 127 ++++++ 13 files changed, 2894 insertions(+) create mode 100644 drivers/clk/starfive/Kconfig create mode 100644 drivers/clk/starfive/Makefile create mode 100644 drivers/clk/starfive/clk-starfive-jh7100-audio.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7100.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-aon.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-stg.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-sys.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c create mode 100644 drivers/clk/starfive/clk-starfive-jh7110.h create mode 100644 drivers/clk/starfive/clk-starfive-jh71x0.c create mode 100644 drivers/clk/starfive/clk-starfive-jh71x0.h (limited to 'drivers/clk/starfive') diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig new file mode 100644 index 000000000..bd29358ff --- /dev/null +++ b/drivers/clk/starfive/Kconfig @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0 + +config CLK_STARFIVE_JH71X0 + bool + +config CLK_STARFIVE_JH7100 + bool "StarFive JH7100 clock support" + depends on ARCH_STARFIVE || COMPILE_TEST + select CLK_STARFIVE_JH71X0 + default ARCH_STARFIVE + help + Say yes here to support the clock controller on the StarFive JH7100 + SoC. + +config CLK_STARFIVE_JH7100_AUDIO + tristate "StarFive JH7100 audio clock support" + depends on CLK_STARFIVE_JH7100 + select CLK_STARFIVE_JH71X0 + default m if ARCH_STARFIVE + help + Say Y or M here to support the audio clocks on the StarFive JH7100 + SoC. + +config CLK_STARFIVE_JH7110_PLL + bool "StarFive JH7110 PLL clock support" + depends on ARCH_STARFIVE || COMPILE_TEST + default ARCH_STARFIVE + help + Say yes here to support the PLL clock controller on the + StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_SYS + bool "StarFive JH7110 system clock support" + depends on ARCH_STARFIVE || COMPILE_TEST + select AUXILIARY_BUS + select CLK_STARFIVE_JH71X0 + select RESET_STARFIVE_JH7110 if RESET_CONTROLLER + select CLK_STARFIVE_JH7110_PLL + default ARCH_STARFIVE + help + Say yes here to support the system clock controller on the + StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_AON + tristate "StarFive JH7110 always-on clock support" + depends on CLK_STARFIVE_JH7110_SYS + default m if ARCH_STARFIVE + help + Say yes here to support the always-on clock controller on the + StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_STG + tristate "StarFive JH7110 System-Top-Group clock support" + depends on CLK_STARFIVE_JH7110_SYS + default m if ARCH_STARFIVE + help + Say yes here to support the System-Top-Group clock controller + on the StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_ISP + tristate "StarFive JH7110 Image-Signal-Process clock support" + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU + default m if ARCH_STARFIVE + help + Say yes here to support the Image-Signal-Process clock controller + on the StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_VOUT + tristate "StarFive JH7110 Video-Output clock support" + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU + default m if ARCH_STARFIVE + help + Say yes here to support the Video-Output clock controller + on the StarFive JH7110 SoC. diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile new file mode 100644 index 000000000..199ac0f37 --- /dev/null +++ b/drivers/clk/starfive/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o + +obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o +obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o + +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c new file mode 100644 index 000000000..de1cf717e --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7100 Audio Clock Driver + * + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-starfive-jh71x0.h" + +/* external clocks */ +#define JH7100_AUDCLK_AUDIO_SRC (JH7100_AUDCLK_END + 0) +#define JH7100_AUDCLK_AUDIO_12288 (JH7100_AUDCLK_END + 1) +#define JH7100_AUDCLK_DOM7AHB_BUS (JH7100_AUDCLK_END + 2) +#define JH7100_AUDCLK_I2SADC_BCLK_IOPAD (JH7100_AUDCLK_END + 3) +#define JH7100_AUDCLK_I2SADC_LRCLK_IOPAD (JH7100_AUDCLK_END + 4) +#define JH7100_AUDCLK_I2SDAC_BCLK_IOPAD (JH7100_AUDCLK_END + 5) +#define JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD (JH7100_AUDCLK_END + 6) +#define JH7100_AUDCLK_VAD_INTMEM (JH7100_AUDCLK_END + 7) + +static const struct jh71x0_clk_data jh7100_audclk_data[] = { + JH71X0__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), + JH71X0__GMD(JH7100_AUDCLK_I2S1_MCLK, "i2s1_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), + JH71X0_GATE(JH7100_AUDCLK_I2SADC_APB, "i2sadc_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2SADC_BCLK, "i2sadc_bclk", 31, 2, + JH7100_AUDCLK_ADC_MCLK, + JH7100_AUDCLK_I2SADC_BCLK_IOPAD), + JH71X0__INV(JH7100_AUDCLK_I2SADC_BCLK_N, "i2sadc_bclk_n", JH7100_AUDCLK_I2SADC_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2SADC_LRCLK, "i2sadc_lrclk", 63, 3, + JH7100_AUDCLK_I2SADC_BCLK_N, + JH7100_AUDCLK_I2SADC_LRCLK_IOPAD, + JH7100_AUDCLK_I2SADC_BCLK), + JH71X0_GATE(JH7100_AUDCLK_PDM_APB, "pdm_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_PDM_MCLK, "pdm_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), + JH71X0_GATE(JH7100_AUDCLK_I2SVAD_APB, "i2svad_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_SPDIF, "spdif", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), + JH71X0_GATE(JH7100_AUDCLK_SPDIF_APB, "spdif_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_GATE(JH7100_AUDCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_DAC_MCLK, "dac_mclk", 0, 15, 2, + JH7100_AUDCLK_AUDIO_SRC, + JH7100_AUDCLK_AUDIO_12288), + JH71X0_GATE(JH7100_AUDCLK_I2SDAC_APB, "i2sdac_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_BCLK, "i2sdac_bclk", 31, 2, + JH7100_AUDCLK_DAC_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), + JH71X0__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2, + JH7100_AUDCLK_I2S1_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), + JH71X0_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2, + JH7100_AUDCLK_I2S1_MCLK, + JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), + JH71X0__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3, + JH7100_AUDCLK_I2S1_BCLK_N, + JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD), + JH71X0_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0_GATE(JH7100_AUDCLK_USB_APB, "usb_apb", CLK_IGNORE_UNUSED, JH7100_AUDCLK_APB_EN), + JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), + JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), + JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 0, 2, + JH7100_AUDCLK_VAD_INTMEM, + JH7100_AUDCLK_AUDIO_12288), +}; + +static int jh7100_audclk_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7100_AUDCLK_END), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7100_AUDCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (idx = 0; idx < JH7100_AUDCLK_END; idx++) { + u32 max = jh7100_audclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7100_audclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7100_audclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7100_audclk_data[idx].parents[i]; + + if (pidx < JH7100_AUDCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx == JH7100_AUDCLK_AUDIO_SRC) + parents[i].fw_name = "audio_src"; + else if (pidx == JH7100_AUDCLK_AUDIO_12288) + parents[i].fw_name = "audio_12288"; + else if (pidx == JH7100_AUDCLK_DOM7AHB_BUS) + parents[i].fw_name = "dom7ahb_bus"; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(priv->dev, &clk->hw); + if (ret) + return ret; + } + + return devm_of_clk_add_hw_provider(priv->dev, jh71x0_clk_get, priv); +} + +static const struct of_device_id jh7100_audclk_match[] = { + { .compatible = "starfive,jh7100-audclk" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7100_audclk_match); + +static struct platform_driver jh7100_audclk_driver = { + .probe = jh7100_audclk_probe, + .driver = { + .name = "clk-starfive-jh7100-audio", + .of_match_table = jh7100_audclk_match, + }, +}; +module_platform_driver(jh7100_audclk_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH7100 audio clock driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c new file mode 100644 index 000000000..761e46ed0 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7100 Clock Generator Driver + * + * Copyright 2021 Ahmad Fatoum, Pengutronix + * Copyright (C) 2021 Glider bv + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include +#include +#include +#include + +#include + +#include "clk-starfive-jh71x0.h" + +/* external clocks */ +#define JH7100_CLK_OSC_SYS (JH7100_CLK_END + 0) +#define JH7100_CLK_OSC_AUD (JH7100_CLK_END + 1) +#define JH7100_CLK_GMAC_RMII_REF (JH7100_CLK_END + 2) +#define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) + +static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { + JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 0, 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 0, 4, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT), + JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 0, 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), + JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL1_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 0, 3, + JH7100_CLK_OSC_SYS, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL1_OUT), + JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 0, 3, + JH7100_CLK_OSC_AUD, + JH7100_CLK_PLL0_OUT, + JH7100_CLK_PLL2_OUT), + JH71X0__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), + JH71X0__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), + JH71X0__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), + JH71X0__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), + JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), + JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), + JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_OSC_AUD), + JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), + JH71X0__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), + JH71X0_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), + JH71X0_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), + JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), + JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), + JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), + JH71X0_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), + JH71X0__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), + JH71X0_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), + JH71X0_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), + JH71X0_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), + JH71X0_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), + JH71X0__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), + JH71X0_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), + JH71X0_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), + JH71X0_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, + JH7100_CLK_DDRPLL_DIV2), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, + JH7100_CLK_DDRPLL_DIV4), + JH71X0_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), + JH71X0_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, + JH7100_CLK_DDROSC_DIV2, + JH7100_CLK_DDRPLL_DIV2, + JH7100_CLK_DDRPLL_DIV4, + JH7100_CLK_DDRPLL_DIV8), + JH71X0_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, + JH7100_CLK_DDROSC_DIV2, + JH7100_CLK_DDRPLL_DIV2, + JH7100_CLK_DDRPLL_DIV4, + JH7100_CLK_DDRPLL_DIV8), + JH71X0_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), + JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), + JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 0, 2, + JH7100_CLK_CPU_AXI, + JH7100_CLK_NNEBUS_SRC1), + JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), + JH71X0__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), + JH71X0_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), + JH71X0__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), + JH71X0_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), + JH71X0_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), + JH71X0__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), + JH71X0_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), + JH71X0_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), + JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), + JH71X0__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), + JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), + JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, + JH7100_CLK_USBPHY_ROOTDIV), + JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2, + JH7100_CLK_OSC_SYS, + JH7100_CLK_USBPHY_PLLDIV25M), + JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), + JH71X0_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), + JH71X0_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), + JH71X0_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), + JH71X0__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), + JH71X0_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), + JH71X0__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), + JH71X0_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), + JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), + JH71X0__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), + JH71X0__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), + JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), + JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), + JH71X0_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), + JH71X0__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), + JH71X0_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), + JH71X0__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), + JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), + JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3, + JH7100_CLK_GMAC_GTX, + JH7100_CLK_GMAC_TX_INV, + JH7100_CLK_GMAC_RMII_TX), + JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), + JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 0, 2, + JH7100_CLK_GMAC_GR_MII_RX, + JH7100_CLK_GMAC_RMII_RX), + JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), + JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), +}; + +static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7100_CLK_PLL0_OUT) + return &priv->reg[idx].hw; + + if (idx < JH7100_CLK_END) + return priv->pll[idx - JH7100_CLK_PLL0_OUT]; + + return ERR_PTR(-EINVAL); +} + +static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7100_CLK_PLL0_OUT), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", + "osc_sys", 0, 40, 1); + if (IS_ERR(priv->pll[0])) + return PTR_ERR(priv->pll[0]); + + priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", + "osc_sys", 0, 64, 1); + if (IS_ERR(priv->pll[1])) + return PTR_ERR(priv->pll[1]); + + priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", + "pll2_refclk", 0, 55, 1); + if (IS_ERR(priv->pll[2])) + return PTR_ERR(priv->pll[2]); + + for (idx = 0; idx < JH7100_CLK_PLL0_OUT; idx++) { + u32 max = jh7100_clk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7100_clk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7100_clk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7100_clk_data[idx].parents[i]; + + if (pidx < JH7100_CLK_PLL0_OUT) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx < JH7100_CLK_END) + parents[i].hw = priv->pll[pidx - JH7100_CLK_PLL0_OUT]; + else if (pidx == JH7100_CLK_OSC_SYS) + parents[i].fw_name = "osc_sys"; + else if (pidx == JH7100_CLK_OSC_AUD) + parents[i].fw_name = "osc_aud"; + else if (pidx == JH7100_CLK_GMAC_RMII_REF) + parents[i].fw_name = "gmac_rmii_ref"; + else if (pidx == JH7100_CLK_GMAC_GR_MII_RX) + parents[i].fw_name = "gmac_gr_mii_rxclk"; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(priv->dev, &clk->hw); + if (ret) + return ret; + } + + return devm_of_clk_add_hw_provider(priv->dev, jh7100_clk_get, priv); +} + +static const struct of_device_id clk_starfive_jh7100_match[] = { + { .compatible = "starfive,jh7100-clkgen" }, + { /* sentinel */ } +}; + +static struct platform_driver clk_starfive_jh7100_driver = { + .driver = { + .name = "clk-starfive-jh7100", + .of_match_table = clk_starfive_jh7100_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(clk_starfive_jh7100_driver, clk_starfive_jh7100_probe); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-aon.c b/drivers/clk/starfive/clk-starfive-jh7110-aon.c new file mode 100644 index 000000000..6f67587f4 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Always-On Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include +#include +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_AONCLK_OSC (JH7110_AONCLK_END + 0) +#define JH7110_AONCLK_GMAC0_RMII_REFIN (JH7110_AONCLK_END + 1) +#define JH7110_AONCLK_GMAC0_RGMII_RXIN (JH7110_AONCLK_END + 2) +#define JH7110_AONCLK_STG_AXIAHB (JH7110_AONCLK_END + 3) +#define JH7110_AONCLK_APB_BUS (JH7110_AONCLK_END + 4) +#define JH7110_AONCLK_GMAC0_GTXCLK (JH7110_AONCLK_END + 5) +#define JH7110_AONCLK_RTC_OSC (JH7110_AONCLK_END + 6) + +static const struct jh71x0_clk_data jh7110_aonclk_data[] = { + /* source */ + JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC), + JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2, + JH7110_AONCLK_OSC_DIV4, + JH7110_AONCLK_OSC), + /* gmac0 */ + JH71X0_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", 0, JH7110_AONCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", 0, JH7110_AONCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx", 30, + JH7110_AONCLK_GMAC0_RMII_REFIN), + JH71X0_GMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, + JH7110_AONCLK_GMAC0_GTXCLK, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX), + JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2, + JH7110_AONCLK_GMAC0_RGMII_RXIN, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX), + /* otpc */ + JH71X0_GATE(JH7110_AONCLK_OTPC_APB, "otpc_apb", 0, JH7110_AONCLK_APB_BUS), + /* rtc */ + JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS), + JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC), + JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2, + JH7110_AONCLK_RTC_OSC, + JH7110_AONCLK_RTC_INTERNAL), + JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC), +}; + +static int jh7110_aoncrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_AONCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7110_AONCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (idx = 0; idx < JH7110_AONCLK_END; idx++) { + u32 max = jh7110_aonclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_aonclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_aonclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_aonclk_data[idx].parents[i]; + + if (pidx < JH7110_AONCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx == JH7110_AONCLK_OSC) + parents[i].fw_name = "osc"; + else if (pidx == JH7110_AONCLK_GMAC0_RMII_REFIN) + parents[i].fw_name = "gmac0_rmii_refin"; + else if (pidx == JH7110_AONCLK_GMAC0_RGMII_RXIN) + parents[i].fw_name = "gmac0_rgmii_rxin"; + else if (pidx == JH7110_AONCLK_STG_AXIAHB) + parents[i].fw_name = "stg_axiahb"; + else if (pidx == JH7110_AONCLK_APB_BUS) + parents[i].fw_name = "apb_bus"; + else if (pidx == JH7110_AONCLK_GMAC0_GTXCLK) + parents[i].fw_name = "gmac0_gtxclk"; + else if (pidx == JH7110_AONCLK_RTC_OSC) + parents[i].fw_name = "rtc_osc"; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv); + if (ret) + return ret; + + return jh7110_reset_controller_register(priv, "rst-aon", 1); +} + +static const struct of_device_id jh7110_aoncrg_match[] = { + { .compatible = "starfive,jh7110-aoncrg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_aoncrg_match); + +static struct platform_driver jh7110_aoncrg_driver = { + .probe = jh7110_aoncrg_probe, + .driver = { + .name = "clk-starfive-jh7110-aon", + .of_match_table = jh7110_aoncrg_match, + }, +}; +module_platform_driver(jh7110_aoncrg_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH7110 always-on clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c new file mode 100644 index 000000000..f3fa069db --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Image-Signal-Process Clock Driver + * + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0) +#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1) +#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2) +#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3) +#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4) + +static struct clk_bulk_data jh7110_isp_top_clks[] = { + { .id = "isp_top_core" }, + { .id = "isp_top_axi" } +}; + +static const struct jh71x0_clk_data jh7110_ispclk_data[] = { + /* syscon */ + JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15, + JH7110_ISPCLK_ISP_TOP_AXI), + JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8, + JH7110_ISPCLK_ISP_TOP_CORE), + JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK), + /* vin */ + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFG_IN, "m31dphy_cfg_in", 16, + JH7110_ISPCLK_ISP_TOP_CORE), + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REF_IN, "m31dphy_ref_in", 16, + JH7110_ISPCLK_ISP_TOP_CORE), + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0, "m31dphy_tx_esc_lan0", 60, + JH7110_ISPCLK_ISP_TOP_CORE), + JH71X0_GATE(JH7110_ISPCLK_VIN_APB, "vin_apb", 0, + JH7110_ISPCLK_DOM4_APB_FUNC), + JH71X0__DIV(JH7110_ISPCLK_VIN_SYS, "vin_sys", 8, JH7110_ISPCLK_ISP_TOP_CORE), + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF0, "vin_pixel_if0", 0, + JH7110_ISPCLK_MIPI_RX0_PXL), + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF1, "vin_pixel_if1", 0, + JH7110_ISPCLK_MIPI_RX0_PXL), + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF2, "vin_pixel_if2", 0, + JH7110_ISPCLK_MIPI_RX0_PXL), + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0, + JH7110_ISPCLK_MIPI_RX0_PXL), + JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 0, 2, + JH7110_ISPCLK_MIPI_RX0_PXL, + JH7110_ISPCLK_DVP_INV), + /* ispv2_top_wrapper */ + JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C, "ispv2_top_wrapper_c", 0, 2, + JH7110_ISPCLK_MIPI_RX0_PXL, + JH7110_ISPCLK_DVP_INV), +}; + +static inline int jh7110_isp_top_rst_init(struct jh71x0_clk_priv *priv) +{ + struct reset_control *top_rsts; + + /* The resets should be shared and other ISP modules will use its. */ + top_rsts = devm_reset_control_array_get_shared(priv->dev); + if (IS_ERR(top_rsts)) + return dev_err_probe(priv->dev, PTR_ERR(top_rsts), + "failed to get top resets\n"); + + return reset_control_deassert(top_rsts); +} + +#ifdef CONFIG_PM +static int jh7110_ispcrg_suspend(struct device *dev) +{ + struct jh7110_top_sysclk *top = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks); + + return 0; +} + +static int jh7110_ispcrg_resume(struct device *dev) +{ + struct jh7110_top_sysclk *top = dev_get_drvdata(dev); + + return clk_bulk_prepare_enable(top->top_clks_num, top->top_clks); +} + +static const struct dev_pm_ops jh7110_ispcrg_pm_ops = { + RUNTIME_PM_OPS(jh7110_ispcrg_suspend, jh7110_ispcrg_resume, NULL) +}; +#endif + +static int jh7110_ispcrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + struct jh7110_top_sysclk *top; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_ISPCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL); + if (!top) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7110_ISPCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + top->top_clks = jh7110_isp_top_clks; + top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks); + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks); + if (ret) + return dev_err_probe(priv->dev, ret, "failed to get main clocks\n"); + dev_set_drvdata(priv->dev, top); + + /* enable power domain and clocks */ + pm_runtime_enable(priv->dev); + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) + return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); + + ret = jh7110_isp_top_rst_init(priv); + if (ret) + goto err_exit; + + for (idx = 0; idx < JH7110_ISPCLK_END; idx++) { + u32 max = jh7110_ispclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_ispclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_ispclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + const char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = { + "isp_top_core", + "isp_top_axi", + "noc_bus_isp_axi", + "dvp_clk" + }; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_ispclk_data[idx].parents[i]; + + if (pidx < JH7110_ISPCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else + parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END]; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + goto err_exit; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv); + if (ret) + goto err_exit; + + ret = jh7110_reset_controller_register(priv, "rst-isp", 3); + if (ret) + goto err_exit; + + return 0; + +err_exit: + pm_runtime_put_sync(priv->dev); + pm_runtime_disable(priv->dev); + return ret; +} + +static void jh7110_ispcrg_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); +} + +static const struct of_device_id jh7110_ispcrg_match[] = { + { .compatible = "starfive,jh7110-ispcrg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match); + +static struct platform_driver jh7110_ispcrg_driver = { + .probe = jh7110_ispcrg_probe, + .remove = jh7110_ispcrg_remove, + .driver = { + .name = "clk-starfive-jh7110-isp", + .of_match_table = jh7110_ispcrg_match, + .pm = pm_ptr(&jh7110_ispcrg_pm_ops), + }, +}; +module_platform_driver(jh7110_ispcrg_driver); + +MODULE_AUTHOR("Xingyu Wu "); +MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c new file mode 100644 index 000000000..56dc58a04 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 PLL Clock Generator Driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Copyright (C) 2023 Emil Renner Berthing + * + * This driver is about to register JH7110 PLL clock generator and support ops. + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2. + * Each PLL clocks work in integer mode or fraction mode by some dividers, + * and the configuration registers and dividers are set in several syscon registers. + * The formula for calculating frequency is: + * Fvco = Fref * (NI + NF) / M / Q1 + * Fref: OSC source clock rate + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0]. + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999. + * M: frequency dividing ratio of pre-divider, set by prediv[5:0]. + * Q1: frequency dividing ratio of post divider, set by 2^postdiv1[1:0], eg. 1, 2, 4 or 8. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* this driver expects a 24MHz input frequency from the oscillator */ +#define JH7110_PLL_OSC_RATE 24000000UL + +#define JH7110_PLL0_PD_OFFSET 0x18 +#define JH7110_PLL0_DACPD_SHIFT 24 +#define JH7110_PLL0_DACPD_MASK BIT(24) +#define JH7110_PLL0_DSMPD_SHIFT 25 +#define JH7110_PLL0_DSMPD_MASK BIT(25) +#define JH7110_PLL0_FBDIV_OFFSET 0x1c +#define JH7110_PLL0_FBDIV_SHIFT 0 +#define JH7110_PLL0_FBDIV_MASK GENMASK(11, 0) +#define JH7110_PLL0_FRAC_OFFSET 0x20 +#define JH7110_PLL0_PREDIV_OFFSET 0x24 + +#define JH7110_PLL1_PD_OFFSET 0x24 +#define JH7110_PLL1_DACPD_SHIFT 15 +#define JH7110_PLL1_DACPD_MASK BIT(15) +#define JH7110_PLL1_DSMPD_SHIFT 16 +#define JH7110_PLL1_DSMPD_MASK BIT(16) +#define JH7110_PLL1_FBDIV_OFFSET 0x24 +#define JH7110_PLL1_FBDIV_SHIFT 17 +#define JH7110_PLL1_FBDIV_MASK GENMASK(28, 17) +#define JH7110_PLL1_FRAC_OFFSET 0x28 +#define JH7110_PLL1_PREDIV_OFFSET 0x2c + +#define JH7110_PLL2_PD_OFFSET 0x2c +#define JH7110_PLL2_DACPD_SHIFT 15 +#define JH7110_PLL2_DACPD_MASK BIT(15) +#define JH7110_PLL2_DSMPD_SHIFT 16 +#define JH7110_PLL2_DSMPD_MASK BIT(16) +#define JH7110_PLL2_FBDIV_OFFSET 0x2c +#define JH7110_PLL2_FBDIV_SHIFT 17 +#define JH7110_PLL2_FBDIV_MASK GENMASK(28, 17) +#define JH7110_PLL2_FRAC_OFFSET 0x30 +#define JH7110_PLL2_PREDIV_OFFSET 0x34 + +#define JH7110_PLL_FRAC_SHIFT 0 +#define JH7110_PLL_FRAC_MASK GENMASK(23, 0) +#define JH7110_PLL_POSTDIV1_SHIFT 28 +#define JH7110_PLL_POSTDIV1_MASK GENMASK(29, 28) +#define JH7110_PLL_PREDIV_SHIFT 0 +#define JH7110_PLL_PREDIV_MASK GENMASK(5, 0) + +enum jh7110_pll_mode { + JH7110_PLL_MODE_FRACTION, + JH7110_PLL_MODE_INTEGER, +}; + +struct jh7110_pll_preset { + unsigned long freq; + u32 frac; /* frac value should be decimals multiplied by 2^24 */ + unsigned fbdiv : 12; /* fbdiv value should be 8 to 4095 */ + unsigned prediv : 6; + unsigned postdiv1 : 2; + unsigned mode : 1; +}; + +struct jh7110_pll_info { + char *name; + const struct jh7110_pll_preset *presets; + unsigned int npresets; + struct { + unsigned int pd; + unsigned int fbdiv; + unsigned int frac; + unsigned int prediv; + } offsets; + struct { + u32 dacpd; + u32 dsmpd; + u32 fbdiv; + } masks; + struct { + char dacpd; + char dsmpd; + char fbdiv; + } shifts; +}; + +#define _JH7110_PLL(_idx, _name, _presets) \ + [_idx] = { \ + .name = _name, \ + .presets = _presets, \ + .npresets = ARRAY_SIZE(_presets), \ + .offsets = { \ + .pd = JH7110_PLL##_idx##_PD_OFFSET, \ + .fbdiv = JH7110_PLL##_idx##_FBDIV_OFFSET, \ + .frac = JH7110_PLL##_idx##_FRAC_OFFSET, \ + .prediv = JH7110_PLL##_idx##_PREDIV_OFFSET, \ + }, \ + .masks = { \ + .dacpd = JH7110_PLL##_idx##_DACPD_MASK, \ + .dsmpd = JH7110_PLL##_idx##_DSMPD_MASK, \ + .fbdiv = JH7110_PLL##_idx##_FBDIV_MASK, \ + }, \ + .shifts = { \ + .dacpd = JH7110_PLL##_idx##_DACPD_SHIFT, \ + .dsmpd = JH7110_PLL##_idx##_DSMPD_SHIFT, \ + .fbdiv = JH7110_PLL##_idx##_FBDIV_SHIFT, \ + }, \ + } +#define JH7110_PLL(idx, name, presets) _JH7110_PLL(idx, name, presets) + +struct jh7110_pll_data { + struct clk_hw hw; + unsigned int idx; +}; + +struct jh7110_pll_priv { + struct device *dev; + struct regmap *regmap; + struct jh7110_pll_data pll[JH7110_PLLCLK_END]; +}; + +struct jh7110_pll_regvals { + u32 dacpd; + u32 dsmpd; + u32 fbdiv; + u32 frac; + u32 postdiv1; + u32 prediv; +}; + +/* + * Because the pll frequency is relatively fixed, + * it cannot be set arbitrarily, so it needs a specific configuration. + * PLL0 frequency should be multiple of 125MHz (USB frequency). + */ +static const struct jh7110_pll_preset jh7110_pll0_presets[] = { + { + .freq = 375000000, + .fbdiv = 125, + .prediv = 8, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 500000000, + .fbdiv = 125, + .prediv = 6, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 625000000, + .fbdiv = 625, + .prediv = 24, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 750000000, + .fbdiv = 125, + .prediv = 4, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 875000000, + .fbdiv = 875, + .prediv = 24, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1000000000, + .fbdiv = 125, + .prediv = 3, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1250000000, + .fbdiv = 625, + .prediv = 12, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1375000000, + .fbdiv = 1375, + .prediv = 24, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1500000000, + .fbdiv = 125, + .prediv = 2, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, +}; + +static const struct jh7110_pll_preset jh7110_pll1_presets[] = { + { + .freq = 1066000000, + .fbdiv = 533, + .prediv = 12, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1200000000, + .fbdiv = 50, + .prediv = 1, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1400000000, + .fbdiv = 350, + .prediv = 6, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1600000000, + .fbdiv = 200, + .prediv = 3, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, +}; + +static const struct jh7110_pll_preset jh7110_pll2_presets[] = { + { + .freq = 1188000000, + .fbdiv = 99, + .prediv = 2, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, { + .freq = 1228800000, + .fbdiv = 256, + .prediv = 5, + .postdiv1 = 0, + .mode = JH7110_PLL_MODE_INTEGER, + }, +}; + +static const struct jh7110_pll_info jh7110_plls[JH7110_PLLCLK_END] = { + JH7110_PLL(JH7110_PLLCLK_PLL0_OUT, "pll0_out", jh7110_pll0_presets), + JH7110_PLL(JH7110_PLLCLK_PLL1_OUT, "pll1_out", jh7110_pll1_presets), + JH7110_PLL(JH7110_PLLCLK_PLL2_OUT, "pll2_out", jh7110_pll2_presets), +}; + +static struct jh7110_pll_data *jh7110_pll_data_from(struct clk_hw *hw) +{ + return container_of(hw, struct jh7110_pll_data, hw); +} + +static struct jh7110_pll_priv *jh7110_pll_priv_from(struct jh7110_pll_data *pll) +{ + return container_of(pll, struct jh7110_pll_priv, pll[pll->idx]); +} + +static void jh7110_pll_regvals_get(struct regmap *regmap, + const struct jh7110_pll_info *info, + struct jh7110_pll_regvals *ret) +{ + u32 val; + + regmap_read(regmap, info->offsets.pd, &val); + ret->dacpd = (val & info->masks.dacpd) >> info->shifts.dacpd; + ret->dsmpd = (val & info->masks.dsmpd) >> info->shifts.dsmpd; + + regmap_read(regmap, info->offsets.fbdiv, &val); + ret->fbdiv = (val & info->masks.fbdiv) >> info->shifts.fbdiv; + + regmap_read(regmap, info->offsets.frac, &val); + ret->frac = (val & JH7110_PLL_FRAC_MASK) >> JH7110_PLL_FRAC_SHIFT; + ret->postdiv1 = (val & JH7110_PLL_POSTDIV1_MASK) >> JH7110_PLL_POSTDIV1_SHIFT; + + regmap_read(regmap, info->offsets.prediv, &val); + ret->prediv = (val & JH7110_PLL_PREDIV_MASK) >> JH7110_PLL_PREDIV_SHIFT; +} + +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); + struct jh7110_pll_regvals val; + unsigned long rate; + + jh7110_pll_regvals_get(priv->regmap, &jh7110_plls[pll->idx], &val); + + /* + * dacpd = dsmpd = 0: fraction mode + * dacpd = dsmpd = 1: integer mode, frac value ignored + * + * rate = parent * (fbdiv + frac/2^24) / prediv / 2^postdiv1 + * = (parent * fbdiv + parent * frac / 2^24) / (prediv * 2^postdiv1) + */ + if (val.dacpd == 0 && val.dsmpd == 0) + rate = parent_rate * val.frac / (1UL << 24); + else if (val.dacpd == 1 && val.dsmpd == 1) + rate = 0; + else + return 0; + + rate += parent_rate * val.fbdiv; + rate /= val.prediv << val.postdiv1; + + return rate; +} + +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); + const struct jh7110_pll_info *info = &jh7110_plls[pll->idx]; + const struct jh7110_pll_preset *selected = &info->presets[0]; + unsigned int idx; + + /* if the parent rate doesn't match our expectations the presets won't work */ + if (req->best_parent_rate != JH7110_PLL_OSC_RATE) { + req->rate = jh7110_pll_recalc_rate(hw, req->best_parent_rate); + return 0; + } + + /* find highest rate lower or equal to the requested rate */ + for (idx = 1; idx < info->npresets; idx++) { + const struct jh7110_pll_preset *val = &info->presets[idx]; + + if (req->rate < val->freq) + break; + + selected = val; + } + + req->rate = selected->freq; + return 0; +} + +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); + const struct jh7110_pll_info *info = &jh7110_plls[pll->idx]; + const struct jh7110_pll_preset *val; + unsigned int idx; + + /* if the parent rate doesn't match our expectations the presets won't work */ + if (parent_rate != JH7110_PLL_OSC_RATE) + return -EINVAL; + + for (idx = 0, val = &info->presets[0]; idx < info->npresets; idx++, val++) { + if (val->freq == rate) + goto found; + } + return -EINVAL; + +found: + if (val->mode == JH7110_PLL_MODE_FRACTION) + regmap_update_bits(priv->regmap, info->offsets.frac, JH7110_PLL_FRAC_MASK, + val->frac << JH7110_PLL_FRAC_SHIFT); + + regmap_update_bits(priv->regmap, info->offsets.pd, info->masks.dacpd, + (u32)val->mode << info->shifts.dacpd); + regmap_update_bits(priv->regmap, info->offsets.pd, info->masks.dsmpd, + (u32)val->mode << info->shifts.dsmpd); + regmap_update_bits(priv->regmap, info->offsets.prediv, JH7110_PLL_PREDIV_MASK, + (u32)val->prediv << JH7110_PLL_PREDIV_SHIFT); + regmap_update_bits(priv->regmap, info->offsets.fbdiv, info->masks.fbdiv, + val->fbdiv << info->shifts.fbdiv); + regmap_update_bits(priv->regmap, info->offsets.frac, JH7110_PLL_POSTDIV1_MASK, + (u32)val->postdiv1 << JH7110_PLL_POSTDIV1_SHIFT); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int jh7110_pll_registers_read(struct seq_file *s, void *unused) +{ + struct jh7110_pll_data *pll = s->private; + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); + struct jh7110_pll_regvals val; + + jh7110_pll_regvals_get(priv->regmap, &jh7110_plls[pll->idx], &val); + + seq_printf(s, "fbdiv=%u\n" + "frac=%u\n" + "prediv=%u\n" + "postdiv1=%u\n" + "dacpd=%u\n" + "dsmpd=%u\n", + val.fbdiv, val.frac, val.prediv, val.postdiv1, + val.dacpd, val.dsmpd); + + return 0; +} + +static int jh7110_pll_registers_open(struct inode *inode, struct file *f) +{ + return single_open(f, jh7110_pll_registers_read, inode->i_private); +} + +static const struct file_operations jh7110_pll_registers_ops = { + .owner = THIS_MODULE, + .open = jh7110_pll_registers_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek +}; + +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry) +{ + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); + + debugfs_create_file("registers", 0400, dentry, pll, + &jh7110_pll_registers_ops); +} +#else +#define jh7110_pll_debug_init NULL +#endif + +static const struct clk_ops jh7110_pll_ops = { + .recalc_rate = jh7110_pll_recalc_rate, + .determine_rate = jh7110_pll_determine_rate, + .set_rate = jh7110_pll_set_rate, + .debug_init = jh7110_pll_debug_init, +}; + +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh7110_pll_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_PLLCLK_END) + return &priv->pll[idx].hw; + + return ERR_PTR(-EINVAL); +} + +static int __init jh7110_pll_probe(struct platform_device *pdev) +{ + struct jh7110_pll_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->regmap = syscon_node_to_regmap(priv->dev->of_node->parent); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + for (idx = 0; idx < JH7110_PLLCLK_END; idx++) { + struct clk_parent_data parents = { + .index = 0, + }; + struct clk_init_data init = { + .name = jh7110_plls[idx].name, + .ops = &jh7110_pll_ops, + .parent_data = &parents, + .num_parents = 1, + .flags = 0, + }; + struct jh7110_pll_data *pll = &priv->pll[idx]; + + pll->hw.init = &init; + pll->idx = idx; + + ret = devm_clk_hw_register(&pdev->dev, &pll->hw); + if (ret) + return ret; + } + + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv); +} + +static const struct of_device_id jh7110_pll_match[] = { + { .compatible = "starfive,jh7110-pll" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_pll_match); + +static struct platform_driver jh7110_pll_driver = { + .driver = { + .name = "clk-starfive-jh7110-pll", + .of_match_table = jh7110_pll_match, + }, +}; +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-stg.c b/drivers/clk/starfive/clk-starfive-jh7110-stg.c new file mode 100644 index 000000000..2a5ad0e07 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-stg.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 System-Top-Group Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include +#include +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_STGCLK_OSC (JH7110_STGCLK_END + 0) +#define JH7110_STGCLK_HIFI4_CORE (JH7110_STGCLK_END + 1) +#define JH7110_STGCLK_STG_AXIAHB (JH7110_STGCLK_END + 2) +#define JH7110_STGCLK_USB_125M (JH7110_STGCLK_END + 3) +#define JH7110_STGCLK_CPU_BUS (JH7110_STGCLK_END + 4) +#define JH7110_STGCLK_HIFI4_AXI (JH7110_STGCLK_END + 5) +#define JH7110_STGCLK_NOCSTG_BUS (JH7110_STGCLK_END + 6) +#define JH7110_STGCLK_APB_BUS (JH7110_STGCLK_END + 7) +#define JH7110_STGCLK_EXT_END (JH7110_STGCLK_END + 8) + +static const struct jh71x0_clk_data jh7110_stgclk_data[] = { + /* hifi4 */ + JH71X0_GATE(JH7110_STGCLK_HIFI4_CLK_CORE, "hifi4_clk_core", 0, + JH7110_STGCLK_HIFI4_CORE), + /* usb */ + JH71X0_GATE(JH7110_STGCLK_USB0_APB, "usb0_apb", 0, JH7110_STGCLK_APB_BUS), + JH71X0_GATE(JH7110_STGCLK_USB0_UTMI_APB, "usb0_utmi_apb", 0, JH7110_STGCLK_APB_BUS), + JH71X0_GATE(JH7110_STGCLK_USB0_AXI, "usb0_axi", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GDIV(JH7110_STGCLK_USB0_LPM, "usb0_lpm", 0, 2, JH7110_STGCLK_OSC), + JH71X0_GDIV(JH7110_STGCLK_USB0_STB, "usb0_stb", 0, 4, JH7110_STGCLK_OSC), + JH71X0_GATE(JH7110_STGCLK_USB0_APP_125, "usb0_app_125", 0, JH7110_STGCLK_USB_125M), + JH71X0__DIV(JH7110_STGCLK_USB0_REFCLK, "usb0_refclk", 2, JH7110_STGCLK_OSC), + /* pci-e */ + JH71X0_GATE(JH7110_STGCLK_PCIE0_AXI_MST0, "pcie0_axi_mst0", 0, + JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_PCIE0_APB, "pcie0_apb", 0, JH7110_STGCLK_APB_BUS), + JH71X0_GATE(JH7110_STGCLK_PCIE0_TL, "pcie0_tl", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_PCIE1_AXI_MST0, "pcie1_axi_mst0", 0, + JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_PCIE1_APB, "pcie1_apb", 0, JH7110_STGCLK_APB_BUS), + JH71X0_GATE(JH7110_STGCLK_PCIE1_TL, "pcie1_tl", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_PCIE_SLV_MAIN, "pcie_slv_main", CLK_IS_CRITICAL, + JH7110_STGCLK_STG_AXIAHB), + /* security */ + JH71X0_GATE(JH7110_STGCLK_SEC_AHB, "sec_ahb", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_SEC_MISC_AHB, "sec_misc_ahb", 0, JH7110_STGCLK_STG_AXIAHB), + /* stg mtrx */ + JH71X0_GATE(JH7110_STGCLK_GRP0_MAIN, "mtrx_grp0_main", CLK_IS_CRITICAL, + JH7110_STGCLK_CPU_BUS), + JH71X0_GATE(JH7110_STGCLK_GRP0_BUS, "mtrx_grp0_bus", CLK_IS_CRITICAL, + JH7110_STGCLK_NOCSTG_BUS), + JH71X0_GATE(JH7110_STGCLK_GRP0_STG, "mtrx_grp0_stg", CLK_IS_CRITICAL, + JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_GRP1_MAIN, "mtrx_grp1_main", CLK_IS_CRITICAL, + JH7110_STGCLK_CPU_BUS), + JH71X0_GATE(JH7110_STGCLK_GRP1_BUS, "mtrx_grp1_bus", CLK_IS_CRITICAL, + JH7110_STGCLK_NOCSTG_BUS), + JH71X0_GATE(JH7110_STGCLK_GRP1_STG, "mtrx_grp1_stg", CLK_IS_CRITICAL, + JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_GRP1_HIFI, "mtrx_grp1_hifi", CLK_IS_CRITICAL, + JH7110_STGCLK_HIFI4_AXI), + /* e24_rvpi */ + JH71X0_GDIV(JH7110_STGCLK_E2_RTC, "e2_rtc", 0, 24, JH7110_STGCLK_OSC), + JH71X0_GATE(JH7110_STGCLK_E2_CORE, "e2_core", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_E2_DBG, "e2_dbg", 0, JH7110_STGCLK_STG_AXIAHB), + /* dw_sgdma1p */ + JH71X0_GATE(JH7110_STGCLK_DMA1P_AXI, "dma1p_axi", 0, JH7110_STGCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_STGCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7110_STGCLK_STG_AXIAHB), +}; + +static int jh7110_stgcrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7110_STGCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7110_STGCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (idx = 0; idx < JH7110_STGCLK_END; idx++) { + u32 max = jh7110_stgclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_stgclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_stgclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + const char *fw_name[JH7110_STGCLK_EXT_END - JH7110_STGCLK_END] = { + "osc", + "hifi4_core", + "stg_axiahb", + "usb_125m", + "cpu_bus", + "hifi4_axi", + "nocstg_bus", + "apb_bus" + }; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_stgclk_data[idx].parents[i]; + + if (pidx < JH7110_STGCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx < JH7110_STGCLK_EXT_END) + parents[i].fw_name = fw_name[pidx - JH7110_STGCLK_END]; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv); + if (ret) + return ret; + + return jh7110_reset_controller_register(priv, "rst-stg", 2); +} + +static const struct of_device_id jh7110_stgcrg_match[] = { + { .compatible = "starfive,jh7110-stgcrg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_stgcrg_match); + +static struct platform_driver jh7110_stgcrg_driver = { + .probe = jh7110_stgcrg_probe, + .driver = { + .name = "clk-starfive-jh7110-stg", + .of_match_table = jh7110_stgcrg_match, + }, +}; +module_platform_driver(jh7110_stgcrg_driver); + +MODULE_AUTHOR("Xingyu Wu "); +MODULE_AUTHOR("Emil Renner Berthing "); +MODULE_DESCRIPTION("StarFive JH7110 System-Top-Group clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c new file mode 100644 index 000000000..03c17cd20 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 System Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_SYSCLK_OSC (JH7110_SYSCLK_END + 0) +#define JH7110_SYSCLK_GMAC1_RMII_REFIN (JH7110_SYSCLK_END + 1) +#define JH7110_SYSCLK_GMAC1_RGMII_RXIN (JH7110_SYSCLK_END + 2) +#define JH7110_SYSCLK_I2STX_BCLK_EXT (JH7110_SYSCLK_END + 3) +#define JH7110_SYSCLK_I2STX_LRCK_EXT (JH7110_SYSCLK_END + 4) +#define JH7110_SYSCLK_I2SRX_BCLK_EXT (JH7110_SYSCLK_END + 5) +#define JH7110_SYSCLK_I2SRX_LRCK_EXT (JH7110_SYSCLK_END + 6) +#define JH7110_SYSCLK_TDM_EXT (JH7110_SYSCLK_END + 7) +#define JH7110_SYSCLK_MCLK_EXT (JH7110_SYSCLK_END + 8) +#define JH7110_SYSCLK_PLL0_OUT (JH7110_SYSCLK_END + 9) +#define JH7110_SYSCLK_PLL1_OUT (JH7110_SYSCLK_END + 10) +#define JH7110_SYSCLK_PLL2_OUT (JH7110_SYSCLK_END + 11) + +static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { + /* root */ + JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT), + JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE), + JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2, + JH7110_SYSCLK_PLL2_OUT, + JH7110_SYSCLK_PLL1_OUT), + JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2, + JH7110_SYSCLK_PLL0_OUT, + JH7110_SYSCLK_PLL2_OUT), + JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_AXI_CFG0, "axi_cfg0", 3, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_STG_AXIAHB, "stg_axiahb", 2, JH7110_SYSCLK_AXI_CFG0), + JH71X0_GATE(JH7110_SYSCLK_AHB0, "ahb0", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_SYSCLK_AHB1, "ahb1", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_SYSCLK_APB_BUS, "apb_bus", 8, JH7110_SYSCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_SYSCLK_APB0, "apb0", CLK_IS_CRITICAL, JH7110_SYSCLK_APB_BUS), + JH71X0__DIV(JH7110_SYSCLK_PLL0_DIV2, "pll0_div2", 2, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV2, "pll1_div2", 2, JH7110_SYSCLK_PLL1_OUT), + JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT), + JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2, + JH7110_SYSCLK_MCLK_INNER, + JH7110_SYSCLK_MCLK_EXT), + JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER), + JH71X0_MDIV(JH7110_SYSCLK_ISP_2X, "isp_2x", 8, 2, + JH7110_SYSCLK_PLL2_OUT, + JH7110_SYSCLK_PLL1_OUT), + JH71X0__DIV(JH7110_SYSCLK_ISP_AXI, "isp_axi", 4, JH7110_SYSCLK_ISP_2X), + JH71X0_GDIV(JH7110_SYSCLK_GCLK0, "gclk0", 0, 62, JH7110_SYSCLK_PLL0_DIV2), + JH71X0_GDIV(JH7110_SYSCLK_GCLK1, "gclk1", 0, 62, JH7110_SYSCLK_PLL1_DIV2), + JH71X0_GDIV(JH7110_SYSCLK_GCLK2, "gclk2", 0, 62, JH7110_SYSCLK_PLL2_DIV2), + /* cores */ + JH71X0_GATE(JH7110_SYSCLK_CORE, "core", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE1, "core1", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE2, "core2", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE3, "core3", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE4, "core4", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_DEBUG, "debug", 0, JH7110_SYSCLK_CPU_BUS), + JH71X0__DIV(JH7110_SYSCLK_RTC_TOGGLE, "rtc_toggle", 6, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TRACE0, "trace0", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE1, "trace1", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE2, "trace2", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE3, "trace3", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE4, "trace4", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE_COM, "trace_com", 0, JH7110_SYSCLK_CPU_BUS), + /* noc */ + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_CPU_AXI, "noc_bus_cpu_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_CPU_BUS), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_AXICFG0_AXI, "noc_bus_axicfg0_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_AXI_CFG0), + /* ddr */ + JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4), + JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4, + JH7110_SYSCLK_OSC_DIV2, + JH7110_SYSCLK_PLL1_DIV2, + JH7110_SYSCLK_PLL1_DIV4, + JH7110_SYSCLK_PLL1_DIV8), + JH71X0_GATE(JH7110_SYSCLK_DDR_AXI, "ddr_axi", CLK_IS_CRITICAL, JH7110_SYSCLK_DDR_BUS), + /* gpu */ + JH71X0__DIV(JH7110_SYSCLK_GPU_CORE, "gpu_core", 7, JH7110_SYSCLK_GPU_ROOT), + JH71X0_GATE(JH7110_SYSCLK_GPU_CORE_CLK, "gpu_core_clk", 0, JH7110_SYSCLK_GPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_GPU_SYS_CLK, "gpu_sys_clk", 0, JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_GPU_APB, "gpu_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_GPU_RTC_TOGGLE, "gpu_rtc_toggle", 0, 12, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_GPU_AXI, "noc_bus_gpu_axi", 0, JH7110_SYSCLK_GPU_CORE), + /* isp */ + JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_CORE, "isp_top_core", 0, JH7110_SYSCLK_ISP_2X), + JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_AXI, "isp_top_axi", 0, JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_ISP_AXI, "noc_bus_isp_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_ISP_AXI), + /* hifi4 */ + JH71X0__DIV(JH7110_SYSCLK_HIFI4_CORE, "hifi4_core", 15, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_HIFI4_AXI, "hifi4_axi", 2, JH7110_SYSCLK_HIFI4_CORE), + /* axi_cfg1 */ + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_MAIN, "axi_cfg1_main", CLK_IS_CRITICAL, + JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_AHB, "axi_cfg1_ahb", CLK_IS_CRITICAL, + JH7110_SYSCLK_AHB0), + /* vout */ + JH71X0_GATE(JH7110_SYSCLK_VOUT_SRC, "vout_src", 0, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_VOUT_AXI, "vout_axi", 7, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_DISP_AXI, "noc_bus_disp_axi", 0, JH7110_SYSCLK_VOUT_AXI), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AHB, "vout_top_ahb", 0, JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AXI, "vout_top_axi", 0, JH7110_SYSCLK_VOUT_AXI), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK, "vout_top_hdmitx0_mclk", 0, + JH7110_SYSCLK_MCLK), + JH71X0__DIV(JH7110_SYSCLK_VOUT_TOP_MIPIPHY_REF, "vout_top_mipiphy_ref", 2, + JH7110_SYSCLK_OSC), + /* jpegc */ + JH71X0__DIV(JH7110_SYSCLK_JPEGC_AXI, "jpegc_axi", 16, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_CODAJ12_AXI, "codaj12_axi", 0, JH7110_SYSCLK_JPEGC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_CODAJ12_CORE, "codaj12_core", 0, 16, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_CODAJ12_APB, "codaj12_apb", 0, JH7110_SYSCLK_APB_BUS), + /* vdec */ + JH71X0__DIV(JH7110_SYSCLK_VDEC_AXI, "vdec_axi", 7, JH7110_SYSCLK_BUS_ROOT), + JH71X0_GATE(JH7110_SYSCLK_WAVE511_AXI, "wave511_axi", 0, JH7110_SYSCLK_VDEC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_WAVE511_BPU, "wave511_bpu", 0, 7, JH7110_SYSCLK_BUS_ROOT), + JH71X0_GDIV(JH7110_SYSCLK_WAVE511_VCE, "wave511_vce", 0, 7, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE511_APB, "wave511_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_VDEC_JPG, "vdec_jpg", 0, JH7110_SYSCLK_JPEGC_AXI), + JH71X0_GATE(JH7110_SYSCLK_VDEC_MAIN, "vdec_main", 0, JH7110_SYSCLK_VDEC_AXI), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VDEC_AXI, "noc_bus_vdec_axi", 0, JH7110_SYSCLK_VDEC_AXI), + /* venc */ + JH71X0__DIV(JH7110_SYSCLK_VENC_AXI, "venc_axi", 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE420L_AXI, "wave420l_axi", 0, JH7110_SYSCLK_VENC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_BPU, "wave420l_bpu", 0, 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_VCE, "wave420l_vce", 0, 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE420L_APB, "wave420l_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VENC_AXI, "noc_bus_venc_axi", 0, JH7110_SYSCLK_VENC_AXI), + /* axi_cfg0 */ + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN_DIV, "axi_cfg0_main_div", CLK_IS_CRITICAL, + JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN, "axi_cfg0_main", CLK_IS_CRITICAL, + JH7110_SYSCLK_AXI_CFG0), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_HIFI4, "axi_cfg0_hifi4", CLK_IS_CRITICAL, + JH7110_SYSCLK_HIFI4_AXI), + /* intmem */ + JH71X0_GATE(JH7110_SYSCLK_AXIMEM2_AXI, "aximem2_axi", 0, JH7110_SYSCLK_AXI_CFG0), + /* qspi */ + JH71X0_GATE(JH7110_SYSCLK_QSPI_AHB, "qspi_ahb", 0, JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_QSPI_APB, "qspi_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0__DIV(JH7110_SYSCLK_QSPI_REF_SRC, "qspi_ref_src", 16, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GMUX(JH7110_SYSCLK_QSPI_REF, "qspi_ref", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_QSPI_REF_SRC), + /* sdio */ + JH71X0_GATE(JH7110_SYSCLK_SDIO0_AHB, "sdio0_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_SDIO1_AHB, "sdio1_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GDIV(JH7110_SYSCLK_SDIO0_SDCARD, "sdio0_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), + JH71X0_GDIV(JH7110_SYSCLK_SDIO1_SDCARD, "sdio1_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), + /* stg */ + JH71X0__DIV(JH7110_SYSCLK_USB_125M, "usb_125m", 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_STG_AXI, "noc_bus_stg_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_NOCSTG_BUS), + /* gmac1 */ + JH71X0_GATE(JH7110_SYSCLK_GMAC1_AHB, "gmac1_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_GMAC1_AXI, "gmac1_axi", 0, JH7110_SYSCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_SYSCLK_GMAC_SRC, "gmac_src", 7, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_GMAC1_GTXCLK, "gmac1_gtxclk", 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30, + JH7110_SYSCLK_GMAC1_RMII_REFIN), + JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2, + JH7110_SYSCLK_GMAC1_RGMII_RXIN, + JH7110_SYSCLK_GMAC1_RMII_RTX), + JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX), + JH71X0_GMUX(JH7110_SYSCLK_GMAC1_TX, "gmac1_tx", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, + JH7110_SYSCLK_GMAC1_GTXCLK, + JH7110_SYSCLK_GMAC1_RMII_RTX), + JH71X0__INV(JH7110_SYSCLK_GMAC1_TX_INV, "gmac1_tx_inv", JH7110_SYSCLK_GMAC1_TX), + JH71X0_GATE(JH7110_SYSCLK_GMAC1_GTXC, "gmac1_gtxc", 0, JH7110_SYSCLK_GMAC1_GTXCLK), + /* gmac0 */ + JH71X0_GDIV(JH7110_SYSCLK_GMAC0_GTXCLK, "gmac0_gtxclk", 0, 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GDIV(JH7110_SYSCLK_GMAC0_PTP, "gmac0_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0_GDIV(JH7110_SYSCLK_GMAC_PHY, "gmac_phy", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0_GATE(JH7110_SYSCLK_GMAC0_GTXC, "gmac0_gtxc", 0, JH7110_SYSCLK_GMAC0_GTXCLK), + /* apb misc */ + JH71X0_GATE(JH7110_SYSCLK_IOMUX_APB, "iomux_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_MAILBOX_APB, "mailbox_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_INT_CTRL_APB, "int_ctrl_apb", 0, JH7110_SYSCLK_APB_BUS), + /* can0 */ + JH71X0_GATE(JH7110_SYSCLK_CAN0_APB, "can0_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_CAN0_TIMER, "can0_timer", 0, 24, JH7110_SYSCLK_OSC), + JH71X0_GDIV(JH7110_SYSCLK_CAN0_CAN, "can0_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), + /* can1 */ + JH71X0_GATE(JH7110_SYSCLK_CAN1_APB, "can1_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_CAN1_TIMER, "can1_timer", 0, 24, JH7110_SYSCLK_OSC), + JH71X0_GDIV(JH7110_SYSCLK_CAN1_CAN, "can1_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), + /* pwm */ + JH71X0_GATE(JH7110_SYSCLK_PWM_APB, "pwm_apb", 0, JH7110_SYSCLK_APB_BUS), + /* wdt */ + JH71X0_GATE(JH7110_SYSCLK_WDT_APB, "wdt_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_WDT_CORE, "wdt_core", 0, JH7110_SYSCLK_OSC), + /* timer */ + JH71X0_GATE(JH7110_SYSCLK_TIMER_APB, "timer_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_TIMER0, "timer0", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER1, "timer1", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER2, "timer2", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER3, "timer3", 0, JH7110_SYSCLK_OSC), + /* temp sensor */ + JH71X0_GATE(JH7110_SYSCLK_TEMP_APB, "temp_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_TEMP_CORE, "temp_core", 0, 24, JH7110_SYSCLK_OSC), + /* spi */ + JH71X0_GATE(JH7110_SYSCLK_SPI0_APB, "spi0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI1_APB, "spi1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI2_APB, "spi2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI3_APB, "spi3_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI4_APB, "spi4_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI5_APB, "spi5_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI6_APB, "spi6_apb", 0, JH7110_SYSCLK_APB_BUS), + /* i2c */ + JH71X0_GATE(JH7110_SYSCLK_I2C0_APB, "i2c0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C1_APB, "i2c1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C2_APB, "i2c2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C3_APB, "i2c3_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C4_APB, "i2c4_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C5_APB, "i2c5_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C6_APB, "i2c6_apb", 0, JH7110_SYSCLK_APB_BUS), + /* uart */ + JH71X0_GATE(JH7110_SYSCLK_UART0_APB, "uart0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART0_CORE, "uart0_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART1_APB, "uart1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART1_CORE, "uart1_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART2_APB, "uart2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART2_CORE, "uart2_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART3_APB, "uart3_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART3_CORE, "uart3_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + JH71X0_GATE(JH7110_SYSCLK_UART4_APB, "uart4_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART4_CORE, "uart4_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + JH71X0_GATE(JH7110_SYSCLK_UART5_APB, "uart5_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART5_CORE, "uart5_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + /* pwmdac */ + JH71X0_GATE(JH7110_SYSCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_PWMDAC_CORE, "pwmdac_core", 0, 256, JH7110_SYSCLK_AUDIO_ROOT), + /* spdif */ + JH71X0_GATE(JH7110_SYSCLK_SPDIF_APB, "spdif_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPDIF_CORE, "spdif_core", 0, JH7110_SYSCLK_MCLK), + /* i2stx0 */ + JH71X0_GATE(JH7110_SYSCLK_I2STX0_APB, "i2stx0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2STX0_BCLK_MST, "i2stx0_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_MST_INV, "i2stx0_bclk_mst_inv", + JH7110_SYSCLK_I2STX0_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX0_BCLK_MST_INV, + JH7110_SYSCLK_I2STX0_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2, + JH7110_SYSCLK_I2STX0_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2, + JH7110_SYSCLK_I2STX0_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2stx1 */ + JH71X0_GATE(JH7110_SYSCLK_I2STX1_APB, "i2stx1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2STX1_BCLK_MST, "i2stx1_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_MST_INV, "i2stx1_bclk_mst_inv", + JH7110_SYSCLK_I2STX1_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX1_BCLK_MST_INV, + JH7110_SYSCLK_I2STX1_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2, + JH7110_SYSCLK_I2STX1_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2, + JH7110_SYSCLK_I2STX1_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2srx */ + JH71X0_GATE(JH7110_SYSCLK_I2SRX_APB, "i2srx_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2SRX_BCLK_MST, "i2srx_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_MST_INV, "i2srx_bclk_mst_inv", + JH7110_SYSCLK_I2SRX_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2, + JH7110_SYSCLK_I2SRX_BCLK_MST_INV, + JH7110_SYSCLK_I2SRX_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2, + JH7110_SYSCLK_I2SRX_BCLK_MST, + JH7110_SYSCLK_I2SRX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2, + JH7110_SYSCLK_I2SRX_LRCK_MST, + JH7110_SYSCLK_I2SRX_LRCK_EXT), + /* pdm */ + JH71X0_GDIV(JH7110_SYSCLK_PDM_DMIC, "pdm_dmic", 0, 64, JH7110_SYSCLK_MCLK), + JH71X0_GATE(JH7110_SYSCLK_PDM_APB, "pdm_apb", 0, JH7110_SYSCLK_APB0), + /* tdm */ + JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK), + JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2, + JH7110_SYSCLK_TDM_INTERNAL, + JH7110_SYSCLK_TDM_EXT), + JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM), + /* jtag */ + JH71X0__DIV(JH7110_SYSCLK_JTAG_CERTIFICATION_TRNG, "jtag_certification_trng", 4, + JH7110_SYSCLK_OSC), +}; + +static void jh7110_reset_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static void jh7110_reset_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct jh71x0_reset_adev *rdev = to_jh71x0_reset_adev(adev); + + kfree(rdev); +} + +int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id) +{ + struct jh71x0_reset_adev *rdev; + struct auxiliary_device *adev; + int ret; + + rdev = kzalloc_obj(*rdev); + if (!rdev) + return -ENOMEM; + + rdev->base = priv->base; + + adev = &rdev->adev; + adev->name = adev_name; + adev->dev.parent = priv->dev; + adev->dev.release = jh7110_reset_adev_release; + adev->id = adev_id; + + ret = auxiliary_device_init(adev); + if (ret) + return ret; + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(priv->dev, + jh7110_reset_unregister_adev, adev); +} +EXPORT_SYMBOL_GPL(jh7110_reset_controller_register); + +/* + * This clock notifier is called when the rate of PLL0 clock is to be changed. + * The cpu_root clock should save the current parent clock and switch its parent + * clock to osc before PLL0 rate will be changed. Then switch its parent clock + * back after the PLL0 rate is completed. + */ +static int jh7110_pll0_clk_notifier_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct jh71x0_clk_priv *priv = container_of(nb, struct jh71x0_clk_priv, pll_clk_nb); + struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk; + int ret = 0; + + if (action == PRE_RATE_CHANGE) { + struct clk *osc = clk_get(priv->dev, "osc"); + + priv->original_clk = clk_get_parent(cpu_root); + ret = clk_set_parent(cpu_root, osc); + clk_put(osc); + } else if (action == POST_RATE_CHANGE) { + ret = clk_set_parent(cpu_root, priv->original_clk); + } + + return notifier_from_errno(ret); +} + +static int __init jh7110_syscrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + struct clk *pllclk; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_SYSCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7110_SYSCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + /* Use fixed factor clocks if can not get the PLL clocks from DTS */ + pllclk = clk_get(priv->dev, "pll0_out"); + if (IS_ERR(pllclk)) { + /* 24MHz -> 1000.0MHz */ + priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", + "osc", 0, 125, 3); + if (IS_ERR(priv->pll[0])) + return PTR_ERR(priv->pll[0]); + } else { + priv->pll_clk_nb.notifier_call = jh7110_pll0_clk_notifier_cb; + ret = clk_notifier_register(pllclk, &priv->pll_clk_nb); + if (ret) + return ret; + priv->pll[0] = NULL; + } + + pllclk = clk_get(priv->dev, "pll1_out"); + if (IS_ERR(pllclk)) { + /* 24MHz -> 1066.0MHz */ + priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", + "osc", 0, 533, 12); + if (IS_ERR(priv->pll[1])) + return PTR_ERR(priv->pll[1]); + } else { + clk_put(pllclk); + priv->pll[1] = NULL; + } + + pllclk = clk_get(priv->dev, "pll2_out"); + if (IS_ERR(pllclk)) { + /* 24MHz -> 1188.0MHz */ + priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", + "osc", 0, 99, 2); + if (IS_ERR(priv->pll[2])) + return PTR_ERR(priv->pll[2]); + } else { + clk_put(pllclk); + priv->pll[2] = NULL; + } + + for (idx = 0; idx < JH7110_SYSCLK_END; idx++) { + u32 max = jh7110_sysclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_sysclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_sysclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_sysclk_data[idx].parents[i]; + + if (pidx < JH7110_SYSCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx == JH7110_SYSCLK_OSC) + parents[i].fw_name = "osc"; + else if (pidx == JH7110_SYSCLK_GMAC1_RMII_REFIN) + parents[i].fw_name = "gmac1_rmii_refin"; + else if (pidx == JH7110_SYSCLK_GMAC1_RGMII_RXIN) + parents[i].fw_name = "gmac1_rgmii_rxin"; + else if (pidx == JH7110_SYSCLK_I2STX_BCLK_EXT) + parents[i].fw_name = "i2stx_bclk_ext"; + else if (pidx == JH7110_SYSCLK_I2STX_LRCK_EXT) + parents[i].fw_name = "i2stx_lrck_ext"; + else if (pidx == JH7110_SYSCLK_I2SRX_BCLK_EXT) + parents[i].fw_name = "i2srx_bclk_ext"; + else if (pidx == JH7110_SYSCLK_I2SRX_LRCK_EXT) + parents[i].fw_name = "i2srx_lrck_ext"; + else if (pidx == JH7110_SYSCLK_TDM_EXT) + parents[i].fw_name = "tdm_ext"; + else if (pidx == JH7110_SYSCLK_MCLK_EXT) + parents[i].fw_name = "mclk_ext"; + else if (pidx == JH7110_SYSCLK_PLL0_OUT && !priv->pll[0]) + parents[i].fw_name = "pll0_out"; + else if (pidx == JH7110_SYSCLK_PLL1_OUT && !priv->pll[1]) + parents[i].fw_name = "pll1_out"; + else if (pidx == JH7110_SYSCLK_PLL2_OUT && !priv->pll[2]) + parents[i].fw_name = "pll2_out"; + else + parents[i].hw = priv->pll[pidx - JH7110_SYSCLK_PLL0_OUT]; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv); + if (ret) + return ret; + + return jh7110_reset_controller_register(priv, "rst-sys", 0); +} + +static const struct of_device_id jh7110_syscrg_match[] = { + { .compatible = "starfive,jh7110-syscrg" }, + { /* sentinel */ } +}; + +static struct platform_driver jh7110_syscrg_driver = { + .driver = { + .name = "clk-starfive-jh7110-sys", + .of_match_table = jh7110_syscrg_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(jh7110_syscrg_driver, jh7110_syscrg_probe); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c new file mode 100644 index 000000000..bad20d5d7 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Video-Output Clock Driver + * + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0) +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1) +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2) +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3) +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4) +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5) +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6) + +static struct clk_bulk_data jh7110_vout_top_clks[] = { + { .id = "vout_src" }, + { .id = "vout_top_ahb" } +}; + +static const struct jh71x0_clk_data jh7110_voutclk_data[] = { + /* divider */ + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB), + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC), + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC), + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB), + /* dc8200 */ + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB), + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2, + JH7110_VOUTCLK_DC8200_PIX, + JH7110_VOUTCLK_HDMITX0_PIXELCLK), + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2, + JH7110_VOUTCLK_DC8200_PIX, + JH7110_VOUTCLK_HDMITX0_PIXELCLK), + /* LCD */ + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2, + JH7110_VOUTCLK_DC8200_PIX0, + JH7110_VOUTCLK_DC8200_PIX1), + /* dsiTx */ + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS), + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS), + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2, + JH7110_VOUTCLK_DC8200_PIX, + JH7110_VOUTCLK_HDMITX0_PIXELCLK), + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC), + /* mipitx DPHY */ + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0, + JH7110_VOUTCLK_TX_ESC), + /* hdmi */ + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0, + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK), + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0, + JH7110_VOUTCLK_I2STX0_BCLK), + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB), +}; + +static int jh7110_vout_top_rst_init(struct jh71x0_clk_priv *priv) +{ + struct reset_control *top_rst; + + /* The reset should be shared and other Vout modules will use its. */ + top_rst = devm_reset_control_get_shared(priv->dev, NULL); + if (IS_ERR(top_rst)) + return dev_err_probe(priv->dev, PTR_ERR(top_rst), "failed to get top reset\n"); + + return reset_control_deassert(top_rst); +} + +#ifdef CONFIG_PM +static int jh7110_voutcrg_suspend(struct device *dev) +{ + struct jh7110_top_sysclk *top = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks); + + return 0; +} + +static int jh7110_voutcrg_resume(struct device *dev) +{ + struct jh7110_top_sysclk *top = dev_get_drvdata(dev); + + return clk_bulk_prepare_enable(top->top_clks_num, top->top_clks); +} + +static const struct dev_pm_ops jh7110_voutcrg_pm_ops = { + RUNTIME_PM_OPS(jh7110_voutcrg_suspend, jh7110_voutcrg_resume, NULL) +}; +#endif + +static int jh7110_voutcrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + struct jh7110_top_sysclk *top; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_VOUTCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL); + if (!top) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->num_reg = JH7110_VOUTCLK_END; + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + top->top_clks = jh7110_vout_top_clks; + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks); + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks); + if (ret) + return dev_err_probe(priv->dev, ret, "failed to get top clocks\n"); + dev_set_drvdata(priv->dev, top); + + /* enable power domain and clocks */ + pm_runtime_enable(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) + return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); + + ret = jh7110_vout_top_rst_init(priv); + if (ret) + goto err_exit; + + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) { + u32 max = jh7110_voutclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_voutclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_voutclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + const char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = { + "vout_src", + "vout_top_ahb", + "vout_top_axi", + "vout_top_hdmitx0_mclk", + "i2stx0_bclk", + "hdmitx0_pixelclk" + }; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_voutclk_data[idx].parents[i]; + + if (pidx < JH7110_VOUTCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx < JH7110_VOUTCLK_EXT_END) + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END]; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + goto err_exit; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv); + if (ret) + goto err_exit; + + ret = jh7110_reset_controller_register(priv, "rst-vo", 4); + if (ret) + goto err_exit; + + return 0; + +err_exit: + pm_runtime_put_sync(priv->dev); + pm_runtime_disable(priv->dev); + return ret; +} + +static void jh7110_voutcrg_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); +} + +static const struct of_device_id jh7110_voutcrg_match[] = { + { .compatible = "starfive,jh7110-voutcrg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match); + +static struct platform_driver jh7110_voutcrg_driver = { + .probe = jh7110_voutcrg_probe, + .remove = jh7110_voutcrg_remove, + .driver = { + .name = "clk-starfive-jh7110-vout", + .of_match_table = jh7110_voutcrg_match, + .pm = pm_ptr(&jh7110_voutcrg_pm_ops), + }, +}; +module_platform_driver(jh7110_voutcrg_driver); + +MODULE_AUTHOR("Xingyu Wu "); +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/starfive/clk-starfive-jh7110.h b/drivers/clk/starfive/clk-starfive-jh7110.h new file mode 100644 index 000000000..0659adae4 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __CLK_STARFIVE_JH7110_H +#define __CLK_STARFIVE_JH7110_H + +#include "clk-starfive-jh71x0.h" + +/* top clocks of ISP/VOUT domain from JH7110 SYSCRG */ +struct jh7110_top_sysclk { + struct clk_bulk_data *top_clks; + int top_clks_num; +}; + +int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id); + +#endif diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.c b/drivers/clk/starfive/clk-starfive-jh71x0.c new file mode 100644 index 000000000..80e915734 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh71x0.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH71X0 Clock Generator Driver + * + * Copyright (C) 2021-2022 Emil Renner Berthing + */ + +#include +#include +#include +#include + +#include "clk-starfive-jh71x0.h" + +static struct jh71x0_clk *jh71x0_clk_from(struct clk_hw *hw) +{ + return container_of(hw, struct jh71x0_clk, hw); +} + +static struct jh71x0_clk_priv *jh71x0_priv_from(struct jh71x0_clk *clk) +{ + return container_of(clk, struct jh71x0_clk_priv, reg[clk->idx]); +} + +static u32 jh71x0_clk_reg_get(struct jh71x0_clk *clk) +{ + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + + return readl_relaxed(reg); +} + +static void jh71x0_clk_reg_rmw(struct jh71x0_clk *clk, u32 mask, u32 value) +{ + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + unsigned long flags; + + spin_lock_irqsave(&priv->rmw_lock, flags); + value |= readl_relaxed(reg) & ~mask; + writel_relaxed(value, reg); + spin_unlock_irqrestore(&priv->rmw_lock, flags); +} + +static int jh71x0_clk_enable(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, JH71X0_CLK_ENABLE); + return 0; +} + +static void jh71x0_clk_disable(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, 0); +} + +static int jh71x0_clk_is_enabled(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + return !!(jh71x0_clk_reg_get(clk) & JH71X0_CLK_ENABLE); +} + +static unsigned long jh71x0_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 div = jh71x0_clk_reg_get(clk) & JH71X0_CLK_DIV_MASK; + + return div ? parent_rate / div : 0; +} + +static int jh71x0_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long parent = req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); + unsigned long result = parent / div; + + /* + * we want the result clamped by min_rate and max_rate if possible: + * case 1: div hits the max divider value, which means it's less than + * parent / rate, so the result is greater than rate and min_rate in + * particular. we can't do anything about result > max_rate because the + * divider doesn't go any further. + * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is + * always lower or equal to rate and max_rate. however the result may + * turn out lower than min_rate, but then the next higher rate is fine: + * div - 1 = ceil(parent / rate) - 1 < parent / rate + * and thus + * min_rate <= rate < parent / (div - 1) + */ + if (result < req->min_rate && div > 1) + result = parent / (div - 1); + + req->rate = result; + return 0; +} + +static int jh71x0_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), + 1UL, (unsigned long)clk->max_div); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, div); + return 0; +} + +static unsigned long jh71x0_clk_frac_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 reg = jh71x0_clk_reg_get(clk); + unsigned long div100 = 100 * (reg & JH71X0_CLK_INT_MASK) + + ((reg & JH71X0_CLK_FRAC_MASK) >> JH71X0_CLK_FRAC_SHIFT); + + return (div100 >= JH71X0_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; +} + +static int jh71x0_clk_frac_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long parent100 = 100 * req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), + JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); + unsigned long result = parent100 / div100; + + /* clamp the result as in jh71x0_clk_determine_rate() above */ + if (result > req->max_rate && div100 < JH71X0_CLK_FRAC_MAX) + result = parent100 / (div100 + 1); + if (result < req->min_rate && div100 > JH71X0_CLK_FRAC_MIN) + result = parent100 / (div100 - 1); + + req->rate = result; + return 0; +} + +static int jh71x0_clk_frac_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), + JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); + u32 value = ((div100 % 100) << JH71X0_CLK_FRAC_SHIFT) | (div100 / 100); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, value); + return 0; +} + +static u8 jh71x0_clk_get_parent(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = jh71x0_clk_reg_get(clk); + + return (value & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT; +} + +static int jh71x0_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = (u32)index << JH71X0_CLK_MUX_SHIFT; + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_MUX_MASK, value); + return 0; +} + +static int jh71x0_clk_get_phase(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = jh71x0_clk_reg_get(clk); + + return (value & JH71X0_CLK_INVERT) ? 180 : 0; +} + +static int jh71x0_clk_set_phase(struct clk_hw *hw, int degrees) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value; + + if (degrees == 0) + value = 0; + else if (degrees == 180) + value = JH71X0_CLK_INVERT; + else + return -EINVAL; + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_INVERT, value); + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void jh71x0_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) +{ + static const struct debugfs_reg32 jh71x0_clk_reg = { + .name = "CTRL", + .offset = 0, + }; + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + struct debugfs_regset32 *regset; + + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return; + + regset->regs = &jh71x0_clk_reg; + regset->nregs = 1; + regset->base = priv->base + 4 * clk->idx; + + debugfs_create_regset32("registers", 0400, dentry, regset); +} +#else +#define jh71x0_clk_debug_init NULL +#endif + +static const struct clk_ops jh71x0_clk_gate_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_div_ops = { + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_fdiv_ops = { + .recalc_rate = jh71x0_clk_frac_recalc_rate, + .determine_rate = jh71x0_clk_frac_determine_rate, + .set_rate = jh71x0_clk_frac_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gdiv_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_mux_ops = { + .determine_rate = __clk_mux_determine_rate, + .set_parent = jh71x0_clk_set_parent, + .get_parent = jh71x0_clk_get_parent, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gmux_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .determine_rate = __clk_mux_determine_rate, + .set_parent = jh71x0_clk_set_parent, + .get_parent = jh71x0_clk_get_parent, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_mdiv_ops = { + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .get_parent = jh71x0_clk_get_parent, + .set_parent = jh71x0_clk_set_parent, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gmd_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .get_parent = jh71x0_clk_get_parent, + .set_parent = jh71x0_clk_set_parent, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_inv_ops = { + .get_phase = jh71x0_clk_get_phase, + .set_phase = jh71x0_clk_set_phase, + .debug_init = jh71x0_clk_debug_init, +}; + +const struct clk_ops *starfive_jh71x0_clk_ops(u32 max) +{ + if (max & JH71X0_CLK_DIV_MASK) { + if (max & JH71X0_CLK_MUX_MASK) { + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gmd_ops; + return &jh71x0_clk_mdiv_ops; + } + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gdiv_ops; + if (max == JH71X0_CLK_FRAC_MAX) + return &jh71x0_clk_fdiv_ops; + return &jh71x0_clk_div_ops; + } + + if (max & JH71X0_CLK_MUX_MASK) { + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gmux_ops; + return &jh71x0_clk_mux_ops; + } + + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gate_ops; + + return &jh71x0_clk_inv_ops; +} +EXPORT_SYMBOL_GPL(starfive_jh71x0_clk_ops); + +struct clk_hw *jh71x0_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < priv->num_reg) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(jh71x0_clk_get); diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.h b/drivers/clk/starfive/clk-starfive-jh71x0.h new file mode 100644 index 000000000..9d5dec1d5 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh71x0.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __CLK_STARFIVE_JH71X0_H +#define __CLK_STARFIVE_JH71X0_H + +#include +#include +#include +#include + +/* register fields */ +#define JH71X0_CLK_ENABLE BIT(31) +#define JH71X0_CLK_INVERT BIT(30) +#define JH71X0_CLK_MUX_MASK GENMASK(27, 24) +#define JH71X0_CLK_MUX_SHIFT 24 +#define JH71X0_CLK_DIV_MASK GENMASK(23, 0) +#define JH71X0_CLK_FRAC_MASK GENMASK(15, 8) +#define JH71X0_CLK_FRAC_SHIFT 8 +#define JH71X0_CLK_INT_MASK GENMASK(7, 0) + +/* fractional divider min/max */ +#define JH71X0_CLK_FRAC_MIN 100UL +#define JH71X0_CLK_FRAC_MAX 25599UL + +/* clock data */ +struct jh71x0_clk_data { + const char *name; + unsigned long flags; + u32 max; + u8 parents[4]; +}; + +#define JH71X0_GATE(_idx, _name, _flags, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT | (_flags), \ + .max = JH71X0_CLK_ENABLE, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0__DIV(_idx, _name, _max, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = _max, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0_GDIV(_idx, _name, _flags, _max, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | (_max), \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0_FDIV(_idx, _name, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = JH71X0_CLK_FRAC_MAX, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0__MUX(_idx, _name, _flags, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0_GMUX(_idx, _name, _flags, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | \ + (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0_MDIV(_idx, _name, _max, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0__GMD(_idx, _name, _flags, _max, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | \ + (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0__INV(_idx, _name, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT, \ + .max = JH71X0_CLK_INVERT, \ + .parents = { [0] = _parent }, \ +} + +struct jh71x0_clk { + struct clk_hw hw; + unsigned int idx; + unsigned int max_div; +}; + +struct jh71x0_clk_priv { + /* protect clk enable and set rate/parent from happening at the same time */ + spinlock_t rmw_lock; + struct device *dev; + void __iomem *base; + struct clk *original_clk; + struct notifier_block pll_clk_nb; + struct clk_hw *pll[3]; + unsigned int num_reg; + struct jh71x0_clk reg[] __counted_by(num_reg); +}; + +const struct clk_ops *starfive_jh71x0_clk_ops(u32 max); +struct clk_hw *jh71x0_clk_get(struct of_phandle_args *clkspec, void *data); + +#endif -- cgit v1.3.1