diff options
Diffstat (limited to 'drivers')
28 files changed, 1342 insertions, 303 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 93f38a8178ba..59a101e1cf65 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -360,13 +360,6 @@ config COMMON_CLK_PXA help Support for the Marvell PXA SoC. -config COMMON_CLK_OXNAS - bool "Clock driver for the OXNAS SoC Family" - depends on ARCH_OXNAS || COMPILE_TEST - select MFD_SYSCON - help - Support for the OXNAS SoC Family clocks. - config COMMON_CLK_RS9_PCIE tristate "Clock driver for Renesas 9-series PCIe clock generators" depends on I2C diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7cb000549b61..94155999eba3 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -52,7 +52,6 @@ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o -obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o diff --git a/drivers/clk/clk-oxnas.c b/drivers/clk/clk-oxnas.c deleted file mode 100644 index f0e2f5a4c291..000000000000 --- a/drivers/clk/clk-oxnas.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Broadcom - * Copyright (C) 2012 Stephen Warren - * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> - */ - -#include <linux/clk-provider.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/stringify.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> - -#include <dt-bindings/clock/oxsemi,ox810se.h> -#include <dt-bindings/clock/oxsemi,ox820.h> - -/* Standard regmap gate clocks */ -struct clk_oxnas_gate { - struct clk_hw hw; - unsigned int bit; - struct regmap *regmap; -}; - -struct oxnas_stdclk_data { - struct clk_hw_onecell_data *onecell_data; - struct clk_oxnas_gate **gates; - unsigned int ngates; - struct clk_oxnas_pll **plls; - unsigned int nplls; -}; - -/* Regmap offsets */ -#define CLK_STAT_REGOFFSET 0x24 -#define CLK_SET_REGOFFSET 0x2c -#define CLK_CLR_REGOFFSET 0x30 - -static inline struct clk_oxnas_gate *to_clk_oxnas_gate(struct clk_hw *hw) -{ - return container_of(hw, struct clk_oxnas_gate, hw); -} - -static int oxnas_clk_gate_is_enabled(struct clk_hw *hw) -{ - struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); - int ret; - unsigned int val; - - ret = regmap_read(std->regmap, CLK_STAT_REGOFFSET, &val); - if (ret < 0) - return ret; - - return val & BIT(std->bit); -} - -static int oxnas_clk_gate_enable(struct clk_hw *hw) -{ - struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); - - regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit)); - - return 0; -} - -static void oxnas_clk_gate_disable(struct clk_hw *hw) -{ - struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); - - regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit)); -} - -static const struct clk_ops oxnas_clk_gate_ops = { - .enable = oxnas_clk_gate_enable, - .disable = oxnas_clk_gate_disable, - .is_enabled = oxnas_clk_gate_is_enabled, -}; - -static const char *const osc_parents[] = { - "oscillator", -}; - -static const char *const eth_parents[] = { - "gmacclk", -}; - -#define OXNAS_GATE(_name, _bit, _parents) \ -struct clk_oxnas_gate _name = { \ - .bit = (_bit), \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &oxnas_clk_gate_ops, \ - .parent_names = _parents, \ - .num_parents = ARRAY_SIZE(_parents), \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ - }, \ -} - -static OXNAS_GATE(ox810se_leon, 0, osc_parents); -static OXNAS_GATE(ox810se_dma_sgdma, 1, osc_parents); -static OXNAS_GATE(ox810se_cipher, 2, osc_parents); -static OXNAS_GATE(ox810se_sata, 4, osc_parents); -static OXNAS_GATE(ox810se_audio, 5, osc_parents); -static OXNAS_GATE(ox810se_usbmph, 6, osc_parents); -static OXNAS_GATE(ox810se_etha, 7, eth_parents); -static OXNAS_GATE(ox810se_pciea, 8, osc_parents); -static OXNAS_GATE(ox810se_nand, 9, osc_parents); - -static struct clk_oxnas_gate *ox810se_gates[] = { - &ox810se_leon, - &ox810se_dma_sgdma, - &ox810se_cipher, - &ox810se_sata, - &ox810se_audio, - &ox810se_usbmph, - &ox810se_etha, - &ox810se_pciea, - &ox810se_nand, -}; - -static OXNAS_GATE(ox820_leon, 0, osc_parents); -static OXNAS_GATE(ox820_dma_sgdma, 1, osc_parents); -static OXNAS_GATE(ox820_cipher, 2, osc_parents); -static OXNAS_GATE(ox820_sd, 3, osc_parents); -static OXNAS_GATE(ox820_sata, 4, osc_parents); -static OXNAS_GATE(ox820_audio, 5, osc_parents); -static OXNAS_GATE(ox820_usbmph, 6, osc_parents); -static OXNAS_GATE(ox820_etha, 7, eth_parents); -static OXNAS_GATE(ox820_pciea, 8, osc_parents); -static OXNAS_GATE(ox820_nand, 9, osc_parents); -static OXNAS_GATE(ox820_ethb, 10, eth_parents); -static OXNAS_GATE(ox820_pcieb, 11, osc_parents); -static OXNAS_GATE(ox820_ref600, 12, osc_parents); -static OXNAS_GATE(ox820_usbdev, 13, osc_parents); - -static struct clk_oxnas_gate *ox820_gates[] = { - &ox820_leon, - &ox820_dma_sgdma, - &ox820_cipher, - &ox820_sd, - &ox820_sata, - &ox820_audio, - &ox820_usbmph, - &ox820_etha, - &ox820_pciea, - &ox820_nand, - &ox820_etha, - &ox820_pciea, - &ox820_ref600, - &ox820_usbdev, -}; - -static struct clk_hw_onecell_data ox810se_hw_onecell_data = { - .hws = { - [CLK_810_LEON] = &ox810se_leon.hw, - [CLK_810_DMA_SGDMA] = &ox810se_dma_sgdma.hw, - [CLK_810_CIPHER] = &ox810se_cipher.hw, - [CLK_810_SATA] = &ox810se_sata.hw, - [CLK_810_AUDIO] = &ox810se_audio.hw, - [CLK_810_USBMPH] = &ox810se_usbmph.hw, - [CLK_810_ETHA] = &ox810se_etha.hw, - [CLK_810_PCIEA] = &ox810se_pciea.hw, - [CLK_810_NAND] = &ox810se_nand.hw, - }, - .num = ARRAY_SIZE(ox810se_gates), -}; - -static struct clk_hw_onecell_data ox820_hw_onecell_data = { - .hws = { - [CLK_820_LEON] = &ox820_leon.hw, - [CLK_820_DMA_SGDMA] = &ox820_dma_sgdma.hw, - [CLK_820_CIPHER] = &ox820_cipher.hw, - [CLK_820_SD] = &ox820_sd.hw, - [CLK_820_SATA] = &ox820_sata.hw, - [CLK_820_AUDIO] = &ox820_audio.hw, - [CLK_820_USBMPH] = &ox820_usbmph.hw, - [CLK_820_ETHA] = &ox820_etha.hw, - [CLK_820_PCIEA] = &ox820_pciea.hw, - [CLK_820_NAND] = &ox820_nand.hw, - [CLK_820_ETHB] = &ox820_ethb.hw, - [CLK_820_PCIEB] = &ox820_pcieb.hw, - [CLK_820_REF600] = &ox820_ref600.hw, - [CLK_820_USBDEV] = &ox820_usbdev.hw, - }, - .num = ARRAY_SIZE(ox820_gates), -}; - -static struct oxnas_stdclk_data ox810se_stdclk_data = { - .onecell_data = &ox810se_hw_onecell_data, - .gates = ox810se_gates, - .ngates = ARRAY_SIZE(ox810se_gates), -}; - -static struct oxnas_stdclk_data ox820_stdclk_data = { - .onecell_data = &ox820_hw_onecell_data, - .gates = ox820_gates, - .ngates = ARRAY_SIZE(ox820_gates), -}; - -static const struct of_device_id oxnas_stdclk_dt_ids[] = { - { .compatible = "oxsemi,ox810se-stdclk", &ox810se_stdclk_data }, - { .compatible = "oxsemi,ox820-stdclk", &ox820_stdclk_data }, - { } -}; - -static int oxnas_stdclk_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node, *parent_np; - const struct oxnas_stdclk_data *data; - struct regmap *regmap; - int ret; - int i; - - data = of_device_get_match_data(&pdev->dev); - - parent_np = of_get_parent(np); - regmap = syscon_node_to_regmap(parent_np); - of_node_put(parent_np); - if (IS_ERR(regmap)) { - dev_err(&pdev->dev, "failed to have parent regmap\n"); - return PTR_ERR(regmap); - } - - for (i = 0 ; i < data->ngates ; ++i) - data->gates[i]->regmap = regmap; - - for (i = 0; i < data->onecell_data->num; i++) { - if (!data->onecell_data->hws[i]) - continue; - - ret = devm_clk_hw_register(&pdev->dev, - data->onecell_data->hws[i]); - if (ret) - return ret; - } - - return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, - data->onecell_data); -} - -static struct platform_driver oxnas_stdclk_driver = { - .probe = oxnas_stdclk_probe, - .driver = { - .name = "oxnas-stdclk", - .suppress_bind_attrs = true, - .of_match_table = oxnas_stdclk_dt_ids, - }, -}; -builtin_platform_driver(oxnas_stdclk_driver); diff --git a/drivers/clk/renesas/clk-emev2.c b/drivers/clk/renesas/clk-emev2.c index 7807b30a5bbb..37c6f9be5e5b 100644 --- a/drivers/clk/renesas/clk-emev2.c +++ b/drivers/clk/renesas/clk-emev2.c @@ -6,7 +6,6 @@ * Copyright (C) 2012 Magnus Damm */ #include <linux/clk-provider.h> -#include <linux/clkdev.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> @@ -74,7 +73,6 @@ static void __init emev2_smu_clkdiv_init(struct device_node *np) clk = clk_register_divider(NULL, np->name, parent_name, 0, smu_base + reg[0], reg[1], 8, 0, &lock); of_clk_add_provider(np, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, np->full_name, NULL); pr_debug("## %s %pOFn %p\n", __func__, np, clk); } CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv", @@ -92,7 +90,6 @@ static void __init emev2_smu_gclk_init(struct device_node *np) clk = clk_register_gate(NULL, np->name, parent_name, 0, smu_base + reg[0], reg[1], 0, &lock); of_clk_add_provider(np, of_clk_src_simple_get, clk); - clk_register_clkdev(clk, np->full_name, NULL); pr_debug("## %s %pOFn %p\n", __func__, np, clk); } CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init); diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c index ad03c09ebc1f..aba043f999eb 100644 --- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -76,6 +76,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), DEF_GEN3_Z("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_GEN3_Z("zg", R8A774A1_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A774A1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A774A1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A774A1_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -123,6 +124,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { + DEF_MOD("3dge", 112, R8A774A1_CLK_ZG), DEF_MOD("tmu4", 121, R8A774A1_CLK_S0D6), DEF_MOD("tmu3", 122, R8A774A1_CLK_S3D2), DEF_MOD("tmu2", 123, R8A774A1_CLK_S3D2), @@ -213,6 +215,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A774A1_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6), DEF_MOD("i2c5", 919, R8A774A1_CLK_S0D6), + DEF_MOD("adg", 922, R8A774A1_CLK_S0D4), DEF_MOD("iic-pmic", 926, R8A774A1_CLK_CP), DEF_MOD("i2c4", 927, R8A774A1_CLK_S0D6), DEF_MOD("i2c3", 928, R8A774A1_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a774b1-cpg-mssr.c b/drivers/clk/renesas/r8a774b1-cpg-mssr.c index ab087b02ef90..a3244e76f779 100644 --- a/drivers/clk/renesas/r8a774b1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774b1-cpg-mssr.c @@ -73,6 +73,7 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A774B1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("zg", R8A774B1_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A774B1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A774B1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A774B1_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -120,6 +121,7 @@ static const struct cpg_core_clk r8a774b1_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a774b1_mod_clks[] __initconst = { + DEF_MOD("3dge", 112, R8A774B1_CLK_ZG), DEF_MOD("tmu4", 121, R8A774B1_CLK_S0D6), DEF_MOD("tmu3", 122, R8A774B1_CLK_S3D2), DEF_MOD("tmu2", 123, R8A774B1_CLK_S3D2), @@ -209,6 +211,7 @@ static const struct mssr_mod_clk r8a774b1_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A774B1_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774B1_CLK_S0D6), DEF_MOD("i2c5", 919, R8A774B1_CLK_S0D6), + DEF_MOD("adg", 922, R8A774B1_CLK_S0D4), DEF_MOD("iic-pmic", 926, R8A774B1_CLK_CP), DEF_MOD("i2c4", 927, R8A774B1_CLK_S0D6), DEF_MOD("i2c3", 928, R8A774B1_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index c9c8fde0f0a6..870f8c55eb28 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -211,6 +211,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A774C0_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774C0_CLK_S3D2), DEF_MOD("i2c5", 919, R8A774C0_CLK_S3D2), + DEF_MOD("adg", 922, R8A774C0_CLK_ZA2), DEF_MOD("iic-pmic", 926, R8A774C0_CLK_CP), DEF_MOD("i2c4", 927, R8A774C0_CLK_S3D2), DEF_MOD("i2c3", 928, R8A774C0_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a774e1-cpg-mssr.c b/drivers/clk/renesas/r8a774e1-cpg-mssr.c index a790061db877..7158464c80d8 100644 --- a/drivers/clk/renesas/r8a774e1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774e1-cpg-mssr.c @@ -76,6 +76,7 @@ static const struct cpg_core_clk r8a774e1_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A774E1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), DEF_GEN3_Z("z2", R8A774E1_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_GEN3_Z("zg", R8A774E1_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A774E1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A774E1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A774E1_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -124,6 +125,7 @@ static const struct cpg_core_clk r8a774e1_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a774e1_mod_clks[] __initconst = { + DEF_MOD("3dge", 112, R8A774E1_CLK_ZG), DEF_MOD("fdp1-1", 118, R8A774E1_CLK_S0D1), DEF_MOD("fdp1-0", 119, R8A774E1_CLK_S0D1), DEF_MOD("tmu4", 121, R8A774E1_CLK_S0D6), @@ -221,7 +223,7 @@ static const struct mssr_mod_clk r8a774e1_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A774E1_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A774E1_CLK_S0D6), DEF_MOD("i2c5", 919, R8A774E1_CLK_S0D6), - DEF_MOD("adg", 922, R8A774E1_CLK_S0D1), + DEF_MOD("adg", 922, R8A774E1_CLK_S0D4), DEF_MOD("iic-pmic", 926, R8A774E1_CLK_CP), DEF_MOD("i2c4", 927, R8A774E1_CLK_S0D6), DEF_MOD("i2c3", 928, R8A774E1_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 7a585a777d38..ad20b3301ef6 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -79,6 +79,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), DEF_GEN3_Z("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_GEN3_Z("zg", R8A7795_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -128,6 +129,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { }; static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { + DEF_MOD("3dge", 112, R8A7795_CLK_ZG), DEF_MOD("fdp1-1", 118, R8A7795_CLK_S0D1), DEF_MOD("fdp1-0", 119, R8A7795_CLK_S0D1), DEF_MOD("tmu4", 121, R8A7795_CLK_S0D6), @@ -251,6 +253,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("rpc-if", 917, R8A7795_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A7795_CLK_S0D6), DEF_MOD("i2c5", 919, R8A7795_CLK_S0D6), + DEF_MOD("adg", 922, R8A7795_CLK_S0D4), DEF_MOD("i2c-dvfs", 926, R8A7795_CLK_CP), DEF_MOD("i2c4", 927, R8A7795_CLK_S0D6), DEF_MOD("i2c3", 928, R8A7795_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index c4969318508e..e5f9e3e74229 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -81,6 +81,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), DEF_GEN3_Z("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_GEN3_Z("zg", R8A7796_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A7796_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A7796_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -130,6 +131,7 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { }; static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { + DEF_MOD("3dge", 112, R8A7796_CLK_ZG), DEF_MOD("fdp1-0", 119, R8A7796_CLK_S0D1), DEF_MOD("tmu4", 121, R8A7796_CLK_S0D6), DEF_MOD("tmu3", 122, R8A7796_CLK_S3D2), @@ -236,6 +238,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { DEF_MOD("rpc-if", 917, R8A7796_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6), DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6), + DEF_MOD("adg", 922, R8A7796_CLK_S0D4), DEF_MOD("i2c-dvfs", 926, R8A7796_CLK_CP), DEF_MOD("i2c4", 927, R8A7796_CLK_S0D6), DEF_MOD("i2c3", 928, R8A7796_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index 78f6e530848e..219e41abb5df 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -76,6 +76,7 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN3_Z("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("zg", R8A77965_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24), DEF_FIXED("ztr", R8A77965_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A77965_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A77965_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -125,6 +126,7 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { + DEF_MOD("3dge", 112, R8A77965_CLK_ZG), DEF_MOD("fdp1-0", 119, R8A77965_CLK_S0D1), DEF_MOD("tmu4", 121, R8A77965_CLK_S0D6), DEF_MOD("tmu3", 122, R8A77965_CLK_S3D2), @@ -236,6 +238,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A77965_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6), DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6), + DEF_MOD("adg", 922, R8A77965_CLK_S0D4), DEF_MOD("i2c-dvfs", 926, R8A77965_CLK_CP), DEF_MOD("i2c4", 927, R8A77965_CLK_S0D6), DEF_MOD("i2c3", 928, R8A77965_CLK_S0D6), diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c index b666d099365e..b2f82c594925 100644 --- a/drivers/clk/renesas/r8a77990-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c @@ -224,6 +224,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { DEF_MOD("rpc-if", 917, R8A77990_CLK_RPCD2), DEF_MOD("i2c6", 918, R8A77990_CLK_S3D2), DEF_MOD("i2c5", 919, R8A77990_CLK_S3D2), + DEF_MOD("adg", 922, R8A77990_CLK_ZA2), DEF_MOD("i2c-dvfs", 926, R8A77990_CLK_CP), DEF_MOD("i2c4", 927, R8A77990_CLK_S3D2), DEF_MOD("i2c3", 928, R8A77990_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index 3a73f6f911dd..162fa86c81ff 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -181,6 +181,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("can-if1", 915, R8A77995_CLK_S3D4), DEF_MOD("can-if0", 916, R8A77995_CLK_S3D4), DEF_MOD("rpc-if", 917, R8A77995_CLK_RPCD2), + DEF_MOD("adg", 922, R8A77995_CLK_ZA2), DEF_MOD("i2c3", 928, R8A77995_CLK_S3D2), DEF_MOD("i2c2", 929, R8A77995_CLK_S3D2), DEF_MOD("i2c1", 930, R8A77995_CLK_S3D2), diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index 99f72bf590fa..1a7a6d60aca4 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -154,6 +154,8 @@ static struct rzg2l_mod_clk r9a07g043_mod_clks[] = { 0x534, 1), DEF_MOD("ostm2_pclk", R9A07G043_OSTM2_PCLK, R9A07G043_CLK_P0, 0x534, 2), + DEF_MOD("mtu_x_mck", R9A07G043_MTU_X_MCK_MTU3, R9A07G043_CLK_P0, + 0x538, 0), DEF_MOD("wdt0_pclk", R9A07G043_WDT0_PCLK, R9A07G043_CLK_P0, 0x548, 0), DEF_MOD("wdt0_clk", R9A07G043_WDT0_CLK, R9A07G043_OSCCLK, @@ -264,6 +266,7 @@ static struct rzg2l_reset r9a07g043_resets[] = { DEF_RST(R9A07G043_OSTM0_PRESETZ, 0x834, 0), DEF_RST(R9A07G043_OSTM1_PRESETZ, 0x834, 1), DEF_RST(R9A07G043_OSTM2_PRESETZ, 0x834, 2), + DEF_RST(R9A07G043_MTU_X_PRESET_MTU3, 0x838, 0), DEF_RST(R9A07G043_WDT0_PRESETN, 0x848, 0), DEF_RST(R9A07G043_SPI_RST, 0x850, 0), DEF_RST(R9A07G043_SDHI0_IXRST, 0x854, 0), diff --git a/drivers/clk/renesas/r9a09g011-cpg.c b/drivers/clk/renesas/r9a09g011-cpg.c index 3d06baf5061d..dda9f29dff33 100644 --- a/drivers/clk/renesas/r9a09g011-cpg.c +++ b/drivers/clk/renesas/r9a09g011-cpg.c @@ -28,6 +28,8 @@ #define DIV_W DDIV_PACK(0x328, 0, 3) #define SEL_B SEL_PLL_PACK(0x214, 0, 1) +#define SEL_CSI0 SEL_PLL_PACK(0x330, 0, 1) +#define SEL_CSI4 SEL_PLL_PACK(0x330, 4, 1) #define SEL_D SEL_PLL_PACK(0x214, 1, 1) #define SEL_E SEL_PLL_PACK(0x214, 2, 1) #define SEL_SDI SEL_PLL_PACK(0x300, 0, 1) @@ -58,6 +60,8 @@ enum clk_ids { CLK_DIV_W, CLK_SEL_B, CLK_SEL_B_D2, + CLK_SEL_CSI0, + CLK_SEL_CSI4, CLK_SEL_D, CLK_SEL_E, CLK_SEL_SDI, @@ -108,6 +112,7 @@ static const struct clk_div_table dtable_divw[] = { /* Mux clock tables */ static const char * const sel_b[] = { ".main", ".divb" }; +static const char * const sel_csi[] = { ".main_24", ".main" }; static const char * const sel_d[] = { ".main", ".divd" }; static const char * const sel_e[] = { ".main", ".dive" }; static const char * const sel_w[] = { ".main", ".divw" }; @@ -139,6 +144,8 @@ static const struct cpg_core_clk r9a09g011_core_clks[] __initconst = { DEF_MUX_RO(".seld", CLK_SEL_D, SEL_D, sel_d), DEF_MUX_RO(".sele", CLK_SEL_E, SEL_E, sel_e), DEF_MUX(".selsdi", CLK_SEL_SDI, SEL_SDI, sel_sdi), + DEF_MUX(".selcsi0", CLK_SEL_CSI0, SEL_CSI0, sel_csi), + DEF_MUX(".selcsi4", CLK_SEL_CSI4, SEL_CSI4, sel_csi), DEF_MUX(".selw0", CLK_SEL_W0, SEL_W0, sel_w), DEF_FIXED(".selb_d2", CLK_SEL_B_D2, CLK_SEL_B, 1, 2), @@ -196,8 +203,12 @@ static const struct rzg2l_mod_clk r9a09g011_mod_clks[] __initconst = { DEF_MOD("pwm12_clk", R9A09G011_PWM12_CLK, CLK_MAIN, 0x434, 8), DEF_MOD("pwm13_clk", R9A09G011_PWM13_CLK, CLK_MAIN, 0x434, 9), DEF_MOD("pwm14_clk", R9A09G011_PWM14_CLK, CLK_MAIN, 0x434, 10), + DEF_MOD("cperi_grpg", R9A09G011_CPERI_GRPG_PCLK, CLK_SEL_E, 0x438, 0), + DEF_MOD("cperi_grph", R9A09G011_CPERI_GRPH_PCLK, CLK_SEL_E, 0x438, 1), DEF_MOD("urt_pclk", R9A09G011_URT_PCLK, CLK_SEL_E, 0x438, 4), DEF_MOD("urt0_clk", R9A09G011_URT0_CLK, CLK_SEL_W0, 0x438, 5), + DEF_MOD("csi0_clk", R9A09G011_CSI0_CLK, CLK_SEL_CSI0, 0x438, 8), + DEF_MOD("csi4_clk", R9A09G011_CSI4_CLK, CLK_SEL_CSI4, 0x438, 12), DEF_MOD("ca53", R9A09G011_CA53_CLK, CLK_DIV_A, 0x448, 0), }; @@ -215,6 +226,8 @@ static const struct rzg2l_reset r9a09g011_resets[] = { DEF_RST(R9A09G011_TIM_GPB_PRESETN, 0x614, 1), DEF_RST(R9A09G011_TIM_GPC_PRESETN, 0x614, 2), DEF_RST_MON(R9A09G011_PWM_GPF_PRESETN, 0x614, 5, 23), + DEF_RST_MON(R9A09G011_CSI_GPG_PRESETN, 0x614, 6, 22), + DEF_RST_MON(R9A09G011_CSI_GPH_PRESETN, 0x614, 7, 23), DEF_RST(R9A09G011_IIC_GPA_PRESETN, 0x614, 8), DEF_RST(R9A09G011_IIC_GPB_PRESETN, 0x614, 9), DEF_RST_MON(R9A09G011_WDT0_PRESETN, 0x614, 12, 19), @@ -225,6 +238,8 @@ static const unsigned int r9a09g011_crit_mod_clks[] __initconst = { MOD_CLK_BASE + R9A09G011_CPERI_GRPB_PCLK, MOD_CLK_BASE + R9A09G011_CPERI_GRPC_PCLK, MOD_CLK_BASE + R9A09G011_CPERI_GRPF_PCLK, + MOD_CLK_BASE + R9A09G011_CPERI_GRPG_PCLK, + MOD_CLK_BASE + R9A09G011_CPERI_GRPH_PCLK, MOD_CLK_BASE + R9A09G011_GIC_CLK, MOD_CLK_BASE + R9A09G011_SYC_CNT_CLK, MOD_CLK_BASE + R9A09G011_URT_PCLK, diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index b3ef62fa612e..d0129a650941 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -264,11 +264,13 @@ static const struct clk_ops cpg_z_clk_ops = { .set_rate = cpg_z_clk_set_rate, }; -static struct clk * __init cpg_z_clk_register(const char *name, +static struct clk * __init __cpg_z_clk_register(const char *name, const char *parent_name, void __iomem *reg, unsigned int div, - unsigned int offset) + unsigned int offset, + unsigned int fcr, + unsigned int flags) { struct clk_init_data init = {}; struct cpg_z_clk *zclk; @@ -280,11 +282,11 @@ static struct clk * __init cpg_z_clk_register(const char *name, init.name = name; init.ops = &cpg_z_clk_ops; - init.flags = CLK_SET_RATE_PARENT; + init.flags = flags; init.parent_names = &parent_name; init.num_parents = 1; - zclk->reg = reg + CPG_FRQCRC; + zclk->reg = reg + fcr; zclk->kick_reg = reg + CPG_FRQCRB; zclk->hw.init = &init; zclk->mask = GENMASK(offset + 4, offset); @@ -301,6 +303,27 @@ static struct clk * __init cpg_z_clk_register(const char *name, return clk; } +static struct clk * __init cpg_z_clk_register(const char *name, + const char *parent_name, + void __iomem *reg, + unsigned int div, + unsigned int offset) +{ + return __cpg_z_clk_register(name, parent_name, reg, div, offset, + CPG_FRQCRC, CLK_SET_RATE_PARENT); +} + +static struct clk * __init cpg_zg_clk_register(const char *name, + const char *parent_name, + void __iomem *reg, + unsigned int div, + unsigned int offset) +{ + return __cpg_z_clk_register(name, parent_name, reg, div, offset, + CPG_FRQCRB, 0); + +} + static const struct clk_div_table cpg_rpcsrc_div_table[] = { { 2, 5 }, { 3, 6 }, { 0, 0 }, }; @@ -438,6 +461,10 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, return cpg_z_clk_register(core->name, __clk_get_name(parent), base, core->div, core->offset); + case CLK_TYPE_GEN3_ZG: + return cpg_zg_clk_register(core->name, __clk_get_name(parent), + base, core->div, core->offset); + case CLK_TYPE_GEN3_OSC: /* * Clock combining OSC EXTAL predivider and a fixed divider diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 9028bf4295ce..bfdc649bdf12 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -22,6 +22,7 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_R, CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */ CLK_TYPE_GEN3_Z, + CLK_TYPE_GEN3_ZG, CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */ CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */ CLK_TYPE_GEN3_RPCSRC, diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 2996f535b7e8..47f488387f33 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -181,12 +181,6 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, return clk_hw->clk; } -static int rzg2l_cpg_sd_clk_mux_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST); -} - static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) { struct sd_hw_data *hwdata = to_sd_hw_data(hw); @@ -249,7 +243,7 @@ static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) } static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { - .determine_rate = rzg2l_cpg_sd_clk_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate_closest, .set_parent = rzg2l_cpg_sd_clk_mux_set_parent, .get_parent = rzg2l_cpg_sd_clk_mux_get_parent, }; diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig index 5d2333106f13..bd29358ffeec 100644 --- a/drivers/clk/starfive/Kconfig +++ b/drivers/clk/starfive/Kconfig @@ -21,12 +21,21 @@ config CLK_STARFIVE_JH7100_AUDIO 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 @@ -39,3 +48,27 @@ config CLK_STARFIVE_JH7110_AON 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 index f3df7d957b1e..199ac0f37a2f 100644 --- a/drivers/clk/starfive/Makefile +++ b/drivers/clk/starfive/Makefile @@ -4,5 +4,9 @@ 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-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c new file mode 100644 index 000000000000..ce034ed28532 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Image-Signal-Process Clock Driver + * + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <dt-bindings/clock/starfive,jh7110-crg.h> + +#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", 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); +} + +static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_ISPCLK_END) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} + +#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->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, jh7110_ispclk_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 int jh7110_ispcrg_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +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 <xingyu.wu@starfivetech.com>"); +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 000000000000..3598390e8fd0 --- /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 <emil.renner.berthing@canonical.com> + * + * 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 <linux/bits.h> +#include <linux/clk-provider.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/starfive,jh7110-crg.h> + +/* 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 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 000000000000..dafcb7190592 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-stg.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 System-Top-Group Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk> + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <dt-bindings/clock/starfive,jh7110-crg.h> + +#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 struct clk_hw *jh7110_stgclk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_STGCLK_END) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} + +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->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, jh7110_stgclk_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 <xingyu.wu@starfivetech.com>"); +MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>"); +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 index e6031345ef05..3884eff9fe93 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -7,6 +7,7 @@ */ #include <linux/auxiliary_bus.h> +#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/init.h> #include <linux/io.h> @@ -389,6 +390,7 @@ 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), @@ -402,28 +404,42 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - /* - * These PLL clocks are not actually fixed factor clocks and can be - * controlled by the syscon registers of JH7110. They will be dropped - * and registered in the PLL clock driver instead. - */ - /* 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]); - - /* 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]); - - /* 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]); + /* 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 { + clk_put(pllclk); + 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; @@ -462,6 +478,12 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev) 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]; } 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 000000000000..10cc1ec43925 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Video-Output Clock Driver + * + * Copyright (C) 2022-2023 StarFive Technology Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <dt-bindings/clock/starfive,jh7110-crg.h> + +#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); +} + +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_VOUTCLK_END) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} + +#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->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_get_sync(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, jh7110_voutclk_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 int jh7110_voutcrg_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +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 <xingyu.wu@starfivetech.com>"); +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 index f29682b8d400..0659adae4d76 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110.h +++ b/drivers/clk/starfive/clk-starfive-jh7110.h @@ -4,6 +4,12 @@ #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); diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.c b/drivers/clk/starfive/clk-starfive-jh71x0.c index b372083d11c3..aebc99264a0b 100644 --- a/drivers/clk/starfive/clk-starfive-jh71x0.c +++ b/drivers/clk/starfive/clk-starfive-jh71x0.c @@ -174,12 +174,6 @@ static int jh71x0_clk_set_parent(struct clk_hw *hw, u8 index) return 0; } -static int jh71x0_clk_mux_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - return clk_mux_determine_rate_flags(hw, req, 0); -} - static int jh71x0_clk_get_phase(struct clk_hw *hw) { struct jh71x0_clk *clk = jh71x0_clk_from(hw); @@ -261,7 +255,7 @@ static const struct clk_ops jh71x0_clk_gdiv_ops = { }; static const struct clk_ops jh71x0_clk_mux_ops = { - .determine_rate = jh71x0_clk_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate, .set_parent = jh71x0_clk_set_parent, .get_parent = jh71x0_clk_get_parent, .debug_init = jh71x0_clk_debug_init, @@ -271,7 +265,7 @@ 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 = jh71x0_clk_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate, .set_parent = jh71x0_clk_set_parent, .get_parent = jh71x0_clk_get_parent, .debug_init = jh71x0_clk_debug_init, diff --git a/drivers/reset/starfive/reset-starfive-jh7110.c b/drivers/reset/starfive/reset-starfive-jh7110.c index 2d26ae95c8cc..29a43f0f2ad6 100644 --- a/drivers/reset/starfive/reset-starfive-jh7110.c +++ b/drivers/reset/starfive/reset-starfive-jh7110.c @@ -31,6 +31,24 @@ static const struct jh7110_reset_info jh7110_aon_info = { .status_offset = 0x3C, }; +static const struct jh7110_reset_info jh7110_stg_info = { + .nr_resets = JH7110_STGRST_END, + .assert_offset = 0x74, + .status_offset = 0x78, +}; + +static const struct jh7110_reset_info jh7110_isp_info = { + .nr_resets = JH7110_ISPRST_END, + .assert_offset = 0x38, + .status_offset = 0x3C, +}; + +static const struct jh7110_reset_info jh7110_vout_info = { + .nr_resets = JH7110_VOUTRST_END, + .assert_offset = 0x48, + .status_offset = 0x4C, +}; + static int jh7110_reset_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id) { @@ -58,6 +76,18 @@ static const struct auxiliary_device_id jh7110_reset_ids[] = { .name = "clk_starfive_jh7110_sys.rst-aon", .driver_data = (kernel_ulong_t)&jh7110_aon_info, }, + { + .name = "clk_starfive_jh7110_sys.rst-stg", + .driver_data = (kernel_ulong_t)&jh7110_stg_info, + }, + { + .name = "clk_starfive_jh7110_sys.rst-isp", + .driver_data = (kernel_ulong_t)&jh7110_isp_info, + }, + { + .name = "clk_starfive_jh7110_sys.rst-vo", + .driver_data = (kernel_ulong_t)&jh7110_vout_info, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(auxiliary, jh7110_reset_ids); |