diff options
Diffstat (limited to 'drivers/clk')
58 files changed, 2604 insertions, 300 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4026fac9fac3..b41aaed9bd51 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -373,6 +373,7 @@ source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" +source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" source "drivers/clk/sifive/Kconfig" source "drivers/clk/sprd/Kconfig" diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c index c88ee20bee31..cb4a406ed15d 100644 --- a/drivers/clk/at91/at91sam9g45.c +++ b/drivers/clk/at91/at91sam9g45.c @@ -46,13 +46,6 @@ static const struct { { .n = "pck1", .p = "prog1", .id = 9 }, }; -static const struct clk_pcr_layout at91sam9g45_pcr_layout = { - .offset = 0x10c, - .cmd = BIT(12), - .pid_mask = GENMASK(5, 0), - .div_mask = GENMASK(17, 16), -}; - struct pck { char *n; u8 id; diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 8b343e59dc61..910e6e74ae90 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -206,6 +206,7 @@ static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) /** * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock + * @node: device node for the clock */ void __init of_fixed_factor_clk_setup(struct device_node *node) { diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 77499a27c8fb..45501637705c 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -168,6 +168,7 @@ static struct clk_hw *_of_fixed_clk_setup(struct device_node *node) /** * of_fixed_clk_setup() - Setup function for simple fixed rate clock + * @node: device node for the clock */ void __init of_fixed_clk_setup(struct device_node *node) { diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 2ce370c804aa..aa21371f9104 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -267,18 +267,7 @@ static struct platform_driver s2mps11_clk_driver = { .remove = s2mps11_clk_remove, .id_table = s2mps11_clk_id, }; - -static int __init s2mps11_clk_init(void) -{ - return platform_driver_register(&s2mps11_clk_driver); -} -subsys_initcall(s2mps11_clk_init); - -static void __exit s2mps11_clk_cleanup(void) -{ - platform_driver_unregister(&s2mps11_clk_driver); -} -module_exit(s2mps11_clk_cleanup); +module_platform_driver(s2mps11_clk_driver); MODULE_DESCRIPTION("S2MPS11 Clock Driver"); MODULE_AUTHOR("Yadwinder Singh Brar <yadi.brar@samsung.com>"); diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 3d7acab9d280..e0446e66fa64 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -883,11 +883,9 @@ static int si5341_output_set_parent(struct clk_hw *hw, u8 index) static u8 si5341_output_get_parent(struct clk_hw *hw) { struct clk_si5341_output *output = to_clk_si5341_output(hw); - int err; u32 val; - err = regmap_read(output->data->regmap, - SI5341_OUT_MUX_SEL(output), &val); + regmap_read(output->data->regmap, SI5341_OUT_MUX_SEL(output), &val); return val & 0x7; } diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index bdc52364b421..77d18276bfe8 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -571,6 +571,7 @@ static const struct clk_ops da8xx_usb1_clk48_ops = { /** * da8xx_cfgchip_register_usb1_clk48 - Register a new USB 1.1 PHY clock + * @dev: The device * @regmap: The CFGCHIP regmap */ static struct da8xx_usb1_clk48 * diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 2ad26cb927fd..aaf31abe1c8f 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -54,6 +54,8 @@ struct sci_clk_provider { * @provider: Master clock provider * @flags: Flags for the clock * @node: Link for handling clocks probed via DT + * @cached_req: Cached requested freq for determine rate calls + * @cached_res: Cached result freq for determine rate calls */ struct sci_clk { struct clk_hw hw; @@ -63,6 +65,8 @@ struct sci_clk { struct sci_clk_provider *provider; u8 flags; struct list_head node; + unsigned long cached_req; + unsigned long cached_res; }; #define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw) @@ -175,6 +179,11 @@ static int sci_clk_determine_rate(struct clk_hw *hw, int ret; u64 new_rate; + if (clk->cached_req && clk->cached_req == req->rate) { + req->rate = clk->cached_res; + return 0; + } + ret = clk->provider->ops->get_best_match_freq(clk->provider->sci, clk->dev_id, clk->clk_id, @@ -189,6 +198,9 @@ static int sci_clk_determine_rate(struct clk_hw *hw, return ret; } + clk->cached_req = req->rate; + clk->cached_res = new_rate; + req->rate = new_rate; return 0; @@ -209,7 +221,8 @@ static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate, struct sci_clk *clk = to_sci_clk(hw); return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id, - clk->clk_id, rate, rate, rate); + clk->clk_id, rate / 10 * 9, rate, + rate / 10 * 11); } /** @@ -249,6 +262,8 @@ static int sci_clk_set_parent(struct clk_hw *hw, u8 index) { struct sci_clk *clk = to_sci_clk(hw); + clk->cached_req = 0; + return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id, clk->clk_id, index + 1 + clk->clk_id); @@ -522,7 +537,7 @@ static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider) np = of_find_node_with_property(np, *clk_name); if (!np) { clk_name++; - break; + continue; } if (!of_device_is_available(np)) diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index db8db1b3b79d..d77ea5aff292 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -909,7 +909,6 @@ static struct platform_driver clk_mt6765_drv = { .probe = clk_mt6765_probe, .driver = { .name = "clk-mt6765", - .owner = THIS_MODULE, .of_match_table = of_match_clk_mt6765, }, }; diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index f35389a11af1..428eb24ffec5 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -582,7 +582,7 @@ CLK_OF_DECLARE_DRIVER(mtk_infra, "mediatek,mt6797-infracfg", static int mtk_infrasys_init(struct platform_device *pdev) { - int r, i; + int i; struct device_node *node = pdev->dev.of_node; if (!infra_clk_data) { @@ -599,11 +599,7 @@ static int mtk_infrasys_init(struct platform_device *pdev) mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), infra_clk_data); - r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data); - if (r) - return r; - - return 0; + return of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data); } #define MT6797_PLL_FMAX (3000UL * MHZ) diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index b73bdf152836..a0ee079670c7 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -601,7 +601,6 @@ static int mtk_infrasys_init(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct clk_onecell_data *clk_data; - int r; clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); @@ -611,12 +610,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes), clk_data); - r = of_clk_add_provider(node, of_clk_src_onecell_get, - clk_data); - if (r) - return r; - - return 0; + return of_clk_add_provider(node, of_clk_src_onecell_get, + clk_data); } static int mtk_pericfg_init(struct platform_device *pdev) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index dabeb435d067..034da203e8e0 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +menu "Clock support for Amlogic platforms" + depends on ARCH_MESON || COMPILE_TEST + config COMMON_CLK_MESON_REGMAP tristate select REGMAP @@ -41,8 +44,9 @@ config COMMON_CLK_MESON_CPU_DYNDIV select COMMON_CLK_MESON_REGMAP config COMMON_CLK_MESON8B - bool - depends on ARCH_MESON + bool "Meson8 SoC Clock controller support" + depends on ARM + default y select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL @@ -54,8 +58,9 @@ config COMMON_CLK_MESON8B want peripherals and CPU frequency scaling to work. config COMMON_CLK_GXBB - bool - depends on ARCH_MESON + bool "GXBB and GXL SoC clock controllers support" + depends on ARM64 + default y select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_VID_PLL_DIV @@ -69,8 +74,9 @@ config COMMON_CLK_GXBB Say Y if you want peripherals and CPU frequency scaling to work. config COMMON_CLK_AXG - bool - depends on ARCH_MESON + bool "AXG SoC clock controllers support" + depends on ARM64 + default y select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL @@ -84,7 +90,7 @@ config COMMON_CLK_AXG config COMMON_CLK_AXG_AUDIO tristate "Meson AXG Audio Clock Controller Driver" - depends on ARCH_MESON + depends on ARM64 select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_PHASE select COMMON_CLK_MESON_SCLK_DIV @@ -94,8 +100,9 @@ config COMMON_CLK_AXG_AUDIO aka axg, Say Y if you want audio subsystem to work. config COMMON_CLK_G12A - bool - depends on ARCH_MESON + bool "G12 and SM1 SoC clock controllers support" + depends on ARM64 + default y select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL @@ -107,3 +114,4 @@ config COMMON_CLK_G12A help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 devices, aka g12a. Say Y if you want peripherals to work. +endmenu diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 53715e36326c..7c8d02164443 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -147,6 +147,29 @@ }, \ } +#define AUD_SCLK_WS(_name, _reg, _width, _shift_ph, _shift_ws, _pname, \ + _iflags) { \ + .data = &(struct meson_sclk_ws_inv_data) { \ + .ph = { \ + .reg_off = (_reg), \ + .shift = (_shift_ph), \ + .width = (_width), \ + }, \ + .ws = { \ + .reg_off = (_reg), \ + .shift = (_shift_ws), \ + .width = (_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "aud_"#_name, \ + .ops = &meson_clk_phase_ops, \ + .parent_names = (const char *[]){ #_pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + /* Audio Master Clocks */ static const struct clk_parent_data mst_mux_parent_data[] = { { .fw_name = "mst_in0", }, @@ -254,6 +277,10 @@ static const struct clk_parent_data tdm_lrclk_parent_data[] = { AUD_PHASE(tdm##_name##_sclk, _reg, 1, 29, \ aud_tdm##_name##_sclk_post_en, \ CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT) +#define AUD_TDM_SCLK_WS(_name, _reg) \ + AUD_SCLK_WS(tdm##_name##_sclk, _reg, 1, 29, 28, \ + aud_tdm##_name##_sclk_post_en, \ + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT) #define AUD_TDM_LRLCK(_name, _reg) \ AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ @@ -499,12 +526,6 @@ static struct clk_regmap tdmin_c_sclk = AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); static struct clk_regmap tdmin_lb_sclk = AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); -static struct clk_regmap tdmout_a_sclk = - AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); -static struct clk_regmap tdmout_b_sclk = - AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); -static struct clk_regmap tdmout_c_sclk = - AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); static struct clk_regmap tdmin_a_lrclk = AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); @@ -521,6 +542,14 @@ static struct clk_regmap tdmout_b_lrclk = static struct clk_regmap tdmout_c_lrclk = AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +/* AXG Clocks */ +static struct clk_regmap axg_tdmout_a_sclk = + AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap axg_tdmout_b_sclk = + AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap axg_tdmout_c_sclk = + AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + /* AXG/G12A Clocks */ static struct clk_hw axg_aud_top = { .init = &(struct clk_init_data) { @@ -591,7 +620,13 @@ static struct clk_regmap g12a_tdm_sclk_pad_1 = AUD_TDM_PAD_CTRL( static struct clk_regmap g12a_tdm_sclk_pad_2 = AUD_TDM_PAD_CTRL( sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, sclk_pad_ctrl_parent_data); -/* G12a/SM1 clocks */ +static struct clk_regmap g12a_tdmout_a_sclk = + AUD_TDM_SCLK_WS(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static struct clk_regmap g12a_tdmout_b_sclk = + AUD_TDM_SCLK_WS(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static struct clk_regmap g12a_tdmout_c_sclk = + AUD_TDM_SCLK_WS(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + static struct clk_regmap toram = AUD_PCLK_GATE(toram, AUDIO_CLK_GATE_EN, 20); static struct clk_regmap spdifout_b = @@ -889,9 +924,9 @@ static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, - [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw, - [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw, - [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, @@ -1026,9 +1061,9 @@ static struct clk_hw_onecell_data g12a_audio_hw_onecell_data = { [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, - [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw, - [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw, - [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw, [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, @@ -1170,9 +1205,9 @@ static struct clk_hw_onecell_data sm1_audio_hw_onecell_data = { [AUD_CLKID_TDMIN_B_SCLK] = &tdmin_b_sclk.hw, [AUD_CLKID_TDMIN_C_SCLK] = &tdmin_c_sclk.hw, [AUD_CLKID_TDMIN_LB_SCLK] = &tdmin_lb_sclk.hw, - [AUD_CLKID_TDMOUT_A_SCLK] = &tdmout_a_sclk.hw, - [AUD_CLKID_TDMOUT_B_SCLK] = &tdmout_b_sclk.hw, - [AUD_CLKID_TDMOUT_C_SCLK] = &tdmout_c_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &g12a_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &g12a_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &g12a_tdmout_c_sclk.hw, [AUD_CLKID_TDMIN_A_LRCLK] = &tdmin_a_lrclk.hw, [AUD_CLKID_TDMIN_B_LRCLK] = &tdmin_b_lrclk.hw, [AUD_CLKID_TDMIN_C_LRCLK] = &tdmin_c_lrclk.hw, @@ -1209,12 +1244,7 @@ static struct clk_hw_onecell_data sm1_audio_hw_onecell_data = { }; -/* Convenience table to populate regmap in .probe() - * Note that this table is shared between both AXG and G12A, - * with spdifout_b clocks being exclusive to G12A. Since those - * clocks are not declared within the AXG onecell table, we do not - * feel the need to have separate AXG/G12A regmap tables. - */ +/* Convenience table to populate regmap in .probe(). */ static struct clk_regmap *const axg_clk_regmaps[] = { &ddr_arb, &pdm, @@ -1236,6 +1266,130 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &spdifout, &resample, &power_detect, + &mst_a_mclk_sel, + &mst_b_mclk_sel, + &mst_c_mclk_sel, + &mst_d_mclk_sel, + &mst_e_mclk_sel, + &mst_f_mclk_sel, + &mst_a_mclk_div, + &mst_b_mclk_div, + &mst_c_mclk_div, + &mst_d_mclk_div, + &mst_e_mclk_div, + &mst_f_mclk_div, + &mst_a_mclk, + &mst_b_mclk, + &mst_c_mclk, + &mst_d_mclk, + &mst_e_mclk, + &mst_f_mclk, + &spdifout_clk_sel, + &spdifout_clk_div, + &spdifout_clk, + &spdifin_clk_sel, + &spdifin_clk_div, + &spdifin_clk, + &pdm_dclk_sel, + &pdm_dclk_div, + &pdm_dclk, + &pdm_sysclk_sel, + &pdm_sysclk_div, + &pdm_sysclk, + &mst_a_sclk_pre_en, + &mst_b_sclk_pre_en, + &mst_c_sclk_pre_en, + &mst_d_sclk_pre_en, + &mst_e_sclk_pre_en, + &mst_f_sclk_pre_en, + &mst_a_sclk_div, + &mst_b_sclk_div, + &mst_c_sclk_div, + &mst_d_sclk_div, + &mst_e_sclk_div, + &mst_f_sclk_div, + &mst_a_sclk_post_en, + &mst_b_sclk_post_en, + &mst_c_sclk_post_en, + &mst_d_sclk_post_en, + &mst_e_sclk_post_en, + &mst_f_sclk_post_en, + &mst_a_sclk, + &mst_b_sclk, + &mst_c_sclk, + &mst_d_sclk, + &mst_e_sclk, + &mst_f_sclk, + &mst_a_lrclk_div, + &mst_b_lrclk_div, + &mst_c_lrclk_div, + &mst_d_lrclk_div, + &mst_e_lrclk_div, + &mst_f_lrclk_div, + &mst_a_lrclk, + &mst_b_lrclk, + &mst_c_lrclk, + &mst_d_lrclk, + &mst_e_lrclk, + &mst_f_lrclk, + &tdmin_a_sclk_sel, + &tdmin_b_sclk_sel, + &tdmin_c_sclk_sel, + &tdmin_lb_sclk_sel, + &tdmout_a_sclk_sel, + &tdmout_b_sclk_sel, + &tdmout_c_sclk_sel, + &tdmin_a_sclk_pre_en, + &tdmin_b_sclk_pre_en, + &tdmin_c_sclk_pre_en, + &tdmin_lb_sclk_pre_en, + &tdmout_a_sclk_pre_en, + &tdmout_b_sclk_pre_en, + &tdmout_c_sclk_pre_en, + &tdmin_a_sclk_post_en, + &tdmin_b_sclk_post_en, + &tdmin_c_sclk_post_en, + &tdmin_lb_sclk_post_en, + &tdmout_a_sclk_post_en, + &tdmout_b_sclk_post_en, + &tdmout_c_sclk_post_en, + &tdmin_a_sclk, + &tdmin_b_sclk, + &tdmin_c_sclk, + &tdmin_lb_sclk, + &axg_tdmout_a_sclk, + &axg_tdmout_b_sclk, + &axg_tdmout_c_sclk, + &tdmin_a_lrclk, + &tdmin_b_lrclk, + &tdmin_c_lrclk, + &tdmin_lb_lrclk, + &tdmout_a_lrclk, + &tdmout_b_lrclk, + &tdmout_c_lrclk, +}; + +static struct clk_regmap *const g12a_clk_regmaps[] = { + &ddr_arb, + &pdm, + &tdmin_a, + &tdmin_b, + &tdmin_c, + &tdmin_lb, + &tdmout_a, + &tdmout_b, + &tdmout_c, + &frddr_a, + &frddr_b, + &frddr_c, + &toddr_a, + &toddr_b, + &toddr_c, + &loopback, + &spdifin, + &spdifout, + &resample, + &power_detect, &spdifout_b, &mst_a_mclk_sel, &mst_b_mclk_sel, @@ -1328,9 +1482,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &tdmin_b_sclk, &tdmin_c_sclk, &tdmin_lb_sclk, - &tdmout_a_sclk, - &tdmout_b_sclk, - &tdmout_c_sclk, + &g12a_tdmout_a_sclk, + &g12a_tdmout_b_sclk, + &g12a_tdmout_c_sclk, &tdmin_a_lrclk, &tdmin_b_lrclk, &tdmin_c_lrclk, @@ -1465,9 +1619,9 @@ static struct clk_regmap *const sm1_clk_regmaps[] = { &tdmin_b_sclk, &tdmin_c_sclk, &tdmin_lb_sclk, - &tdmout_a_sclk, - &tdmout_b_sclk, - &tdmout_c_sclk, + &g12a_tdmout_a_sclk, + &g12a_tdmout_b_sclk, + &g12a_tdmout_c_sclk, &tdmin_a_lrclk, &tdmin_b_lrclk, &tdmin_c_lrclk, @@ -1713,8 +1867,8 @@ static const struct audioclk_data axg_audioclk_data = { }; static const struct audioclk_data g12a_audioclk_data = { - .regmap_clks = axg_clk_regmaps, - .regmap_clk_num = ARRAY_SIZE(axg_clk_regmaps), + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), .hw_onecell_data = &g12a_audio_hw_onecell_data, .reset_offset = AUDIO_SW_RESET, .reset_num = 26, diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c index fe22e171121a..a6763439f7d2 100644 --- a/drivers/clk/meson/clk-phase.c +++ b/drivers/clk/meson/clk-phase.c @@ -125,6 +125,62 @@ const struct clk_ops meson_clk_triphase_ops = { }; EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); +/* + * This is a special clock for the audio controller. + * This drive a bit clock inverter for which the + * opposite value of the inverter bit needs to be manually + * set into another bit + */ +static inline struct meson_sclk_ws_inv_data * +meson_sclk_ws_inv_data(struct clk_regmap *clk) +{ + return (struct meson_sclk_ws_inv_data *)clk->data; +} + +static int meson_sclk_ws_inv_sync(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + + /* Get phase and sync the inverted value to ws */ + val = meson_parm_read(clk->map, &tph->ph); + meson_parm_write(clk->map, &tph->ws, val ? 0 : 1); + + return 0; +} + +static int meson_sclk_ws_inv_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + + val = meson_parm_read(clk->map, &tph->ph); + + return meson_clk_degrees_from_val(val, tph->ph.width); +} + +static int meson_sclk_ws_inv_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_ws_inv_data *tph = meson_sclk_ws_inv_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, tph->ph.width); + meson_parm_write(clk->map, &tph->ph, val); + meson_parm_write(clk->map, &tph->ws, val ? 0 : 1); + return 0; +} + +const struct clk_ops meson_sclk_ws_inv_ops = { + .init = meson_sclk_ws_inv_sync, + .get_phase = meson_sclk_ws_inv_get_phase, + .set_phase = meson_sclk_ws_inv_set_phase, +}; +EXPORT_SYMBOL_GPL(meson_sclk_ws_inv_ops); + + MODULE_DESCRIPTION("Amlogic phase driver"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-phase.h b/drivers/clk/meson/clk-phase.h index 5579f9ced142..b637b9b227bc 100644 --- a/drivers/clk/meson/clk-phase.h +++ b/drivers/clk/meson/clk-phase.h @@ -20,7 +20,13 @@ struct meson_clk_triphase_data { struct parm ph2; }; +struct meson_sclk_ws_inv_data { + struct parm ph; + struct parm ws; +}; + extern const struct clk_ops meson_clk_phase_ops; extern const struct clk_ops meson_clk_triphase_ops; +extern const struct clk_ops meson_sclk_ws_inv_ops; #endif /* __MESON_CLK_PHASE_H */ diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 9803d44bb157..b814d44917a5 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -298,6 +298,17 @@ static struct clk_regmap g12a_fclk_div2 = { &g12a_fclk_div2_div.hw }, .num_parents = 1, + /* + * Similar to fclk_div3, it seems that this clock is used by + * the resident firmware and is required by the platform to + * operate correctly. + * Until the following condition are met, we need this clock to + * be marked as critical: + * a) Mark the clock used by a firmware resource, if possible + * b) CCF has a clock hand-off mechanism to make the sure the + * clock stays on until the proper driver comes along + */ + .flags = CLK_IS_CRITICAL, }, }; diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c index cede7b4ca3b9..998fc4207b0e 100644 --- a/drivers/clk/mmp/clk-of-pxa1928.c +++ b/drivers/clk/mmp/clk-of-pxa1928.c @@ -68,7 +68,6 @@ static struct mmp_clk_factor_tbl uart_factor_tbl[] = { static void pxa1928_pll_init(struct pxa1928_clk_unit *pxa_unit) { - struct clk *clk; struct mmp_clk_unit *unit = &pxa_unit->unit; mmp_register_fixed_rate_clks(unit, fixed_rate_clks, @@ -77,7 +76,7 @@ static void pxa1928_pll_init(struct pxa1928_clk_unit *pxa_unit) mmp_register_fixed_factor_clks(unit, fixed_factor_clks, ARRAY_SIZE(fixed_factor_clks)); - clk = mmp_clk_register_factor("uart_pll", "pll1_416", + mmp_clk_register_factor("uart_pll", "pll1_416", CLK_SET_RATE_PARENT, pxa_unit->mpmu_base + MPMU_UART_PLL, &uart_factor_masks, uart_factor_tbl, diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 28e8730ce263..18915d668a30 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -30,6 +30,7 @@ config CLK_RENESAS select CLK_R8A77980 if ARCH_R8A77980 select CLK_R8A77990 if ARCH_R8A77990 select CLK_R8A77995 if ARCH_R8A77995 + select CLK_R8A779A0 if ARCH_R8A779A0 select CLK_R9A06G032 if ARCH_R9A06G032 select CLK_SH73A0 if ARCH_SH73A0 @@ -145,6 +146,10 @@ config CLK_R8A77995 bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R8A779A0 + bool "R-Car V3U clock support" if COMPILE_TEST + select CLK_RENESAS_CPG_MSSR + config CLK_R9A06G032 bool "Renesas R9A06G032 clock driver" help @@ -162,7 +167,7 @@ config CLK_RCAR_GEN2_CPG select CLK_RENESAS_CPG_MSSR config CLK_RCAR_GEN3_CPG - bool "R-Car Gen3 CPG clock support" if COMPILE_TEST + bool "R-Car Gen3 and RZ/G2 CPG clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR config CLK_RCAR_USB2_CLOCK_SEL diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index c7c03ab9a6a3..c803912ef2ce 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o +obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o diff --git a/drivers/clk/renesas/r7s9210-cpg-mssr.c b/drivers/clk/renesas/r7s9210-cpg-mssr.c index 443bff08df4c..a85227c248f3 100644 --- a/drivers/clk/renesas/r7s9210-cpg-mssr.c +++ b/drivers/clk/renesas/r7s9210-cpg-mssr.c @@ -214,7 +214,7 @@ const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = { .cpg_clk_register = rza2_cpg_clk_register, /* RZ/A2 has Standby Control Registers */ - .stbyctrl = true, + .reg_layout = CLK_REG_LAYOUT_RZ_A, }; static void __init r7s9210_cpg_mssr_early_init(struct device_node *np) diff --git a/drivers/clk/renesas/r8a7742-cpg-mssr.c b/drivers/clk/renesas/r8a7742-cpg-mssr.c index e919828668a4..e541489bd1cd 100644 --- a/drivers/clk/renesas/r8a7742-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7742-cpg-mssr.c @@ -97,7 +97,8 @@ static const struct mssr_mod_clk r8a7742_mod_clks[] __initconst = { DEF_MOD("tmu0", 125, R8A7742_CLK_CP), DEF_MOD("vsp1du1", 127, R8A7742_CLK_ZS), DEF_MOD("vsp1du0", 128, R8A7742_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7742_CLK_ZS), + DEF_MOD("vspr", 130, R8A7742_CLK_ZS), + DEF_MOD("vsps", 131, R8A7742_CLK_ZS), DEF_MOD("scifa2", 202, R8A7742_CLK_MP), DEF_MOD("scifa1", 203, R8A7742_CLK_MP), DEF_MOD("scifa0", 204, R8A7742_CLK_MP), diff --git a/drivers/clk/renesas/r8a7743-cpg-mssr.c b/drivers/clk/renesas/r8a7743-cpg-mssr.c index c01d9af2525a..0bba12a48d22 100644 --- a/drivers/clk/renesas/r8a7743-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7743-cpg-mssr.c @@ -92,7 +92,7 @@ static const struct mssr_mod_clk r8a7743_mod_clks[] __initconst = { DEF_MOD("tmu0", 125, R8A7743_CLK_CP), DEF_MOD("vsp1du1", 127, R8A7743_CLK_ZS), DEF_MOD("vsp1du0", 128, R8A7743_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7743_CLK_ZS), + DEF_MOD("vsps", 131, R8A7743_CLK_ZS), DEF_MOD("scifa2", 202, R8A7743_CLK_MP), DEF_MOD("scifa1", 203, R8A7743_CLK_MP), DEF_MOD("scifa0", 204, R8A7743_CLK_MP), diff --git a/drivers/clk/renesas/r8a7745-cpg-mssr.c b/drivers/clk/renesas/r8a7745-cpg-mssr.c index 493874e5ebee..dc4a64e8dfb5 100644 --- a/drivers/clk/renesas/r8a7745-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7745-cpg-mssr.c @@ -90,7 +90,7 @@ static const struct mssr_mod_clk r8a7745_mod_clks[] __initconst = { DEF_MOD("cmt0", 124, R8A7745_CLK_R), DEF_MOD("tmu0", 125, R8A7745_CLK_CP), DEF_MOD("vsp1du0", 128, R8A7745_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7745_CLK_ZS), + DEF_MOD("vsps", 131, R8A7745_CLK_ZS), DEF_MOD("scifa2", 202, R8A7745_CLK_MP), DEF_MOD("scifa1", 203, R8A7745_CLK_MP), DEF_MOD("scifa0", 204, R8A7745_CLK_MP), diff --git a/drivers/clk/renesas/r8a77470-cpg-mssr.c b/drivers/clk/renesas/r8a77470-cpg-mssr.c index d81ae65f0d18..f3d6e65011d7 100644 --- a/drivers/clk/renesas/r8a77470-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77470-cpg-mssr.c @@ -85,7 +85,7 @@ static const struct mssr_mod_clk r8a77470_mod_clks[] __initconst = { DEF_MOD("tmu2", 122, R8A77470_CLK_P), DEF_MOD("cmt0", 124, R8A77470_CLK_R), DEF_MOD("vsp1du0", 128, R8A77470_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A77470_CLK_ZS), + DEF_MOD("vsps", 131, R8A77470_CLK_ZS), DEF_MOD("msiof2", 205, R8A77470_CLK_MP), DEF_MOD("msiof1", 208, R8A77470_CLK_MP), DEF_MOD("sys-dmac1", 218, R8A77470_CLK_ZS), diff --git a/drivers/clk/renesas/r8a7790-cpg-mssr.c b/drivers/clk/renesas/r8a7790-cpg-mssr.c index c57cb93f8315..f7d233e0c142 100644 --- a/drivers/clk/renesas/r8a7790-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7790-cpg-mssr.c @@ -108,8 +108,8 @@ static const struct mssr_mod_clk r8a7790_mod_clks[] __initconst = { DEF_MOD("tmu0", 125, R8A7790_CLK_CP), DEF_MOD("vsp1du1", 127, R8A7790_CLK_ZS), DEF_MOD("vsp1du0", 128, R8A7790_CLK_ZS), - DEF_MOD("vsp1-rt", 130, R8A7790_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7790_CLK_ZS), + DEF_MOD("vspr", 130, R8A7790_CLK_ZS), + DEF_MOD("vsps", 131, R8A7790_CLK_ZS), DEF_MOD("scifa2", 202, R8A7790_CLK_MP), DEF_MOD("scifa1", 203, R8A7790_CLK_MP), DEF_MOD("scifa0", 204, R8A7790_CLK_MP), diff --git a/drivers/clk/renesas/r8a7791-cpg-mssr.c b/drivers/clk/renesas/r8a7791-cpg-mssr.c index 65702debcabb..a0de784868da 100644 --- a/drivers/clk/renesas/r8a7791-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7791-cpg-mssr.c @@ -102,7 +102,7 @@ static const struct mssr_mod_clk r8a7791_mod_clks[] __initconst = { DEF_MOD("tmu0", 125, R8A7791_CLK_CP), DEF_MOD("vsp1du1", 127, R8A7791_CLK_ZS), DEF_MOD("vsp1du0", 128, R8A7791_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7791_CLK_ZS), + DEF_MOD("vsps", 131, R8A7791_CLK_ZS), DEF_MOD("scifa2", 202, R8A7791_CLK_MP), DEF_MOD("scifa1", 203, R8A7791_CLK_MP), DEF_MOD("scifa0", 204, R8A7791_CLK_MP), diff --git a/drivers/clk/renesas/r8a7792-cpg-mssr.c b/drivers/clk/renesas/r8a7792-cpg-mssr.c index cf8b84a3a060..77af250876a5 100644 --- a/drivers/clk/renesas/r8a7792-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7792-cpg-mssr.c @@ -88,7 +88,7 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = { DEF_MOD("tmu0", 125, R8A7792_CLK_CP), DEF_MOD("vsp1du1", 127, R8A7792_CLK_ZS), DEF_MOD("vsp1du0", 128, R8A7792_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7792_CLK_ZS), + DEF_MOD("vsps", 131, R8A7792_CLK_ZS), DEF_MOD("msiof1", 208, R8A7792_CLK_MP), DEF_MOD("sys-dmac1", 218, R8A7792_CLK_ZS), DEF_MOD("sys-dmac0", 219, R8A7792_CLK_ZS), diff --git a/drivers/clk/renesas/r8a7794-cpg-mssr.c b/drivers/clk/renesas/r8a7794-cpg-mssr.c index c1948693c5c1..4d7fa26a72c9 100644 --- a/drivers/clk/renesas/r8a7794-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7794-cpg-mssr.c @@ -97,7 +97,7 @@ static const struct mssr_mod_clk r8a7794_mod_clks[] __initconst = { DEF_MOD("cmt0", 124, R8A7794_CLK_R), DEF_MOD("tmu0", 125, R8A7794_CLK_CP), DEF_MOD("vsp1du0", 128, R8A7794_CLK_ZS), - DEF_MOD("vsp1-sy", 131, R8A7794_CLK_ZS), + DEF_MOD("vsps", 131, R8A7794_CLK_ZS), DEF_MOD("scifa2", 202, R8A7794_CLK_MP), DEF_MOD("scifa1", 203, R8A7794_CLK_MP), DEF_MOD("scifa0", 204, R8A7794_CLK_MP), diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c new file mode 100644 index 000000000000..17ebbac7ddfb --- /dev/null +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * r8a779a0 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2020 Renesas Electronics Corp. + * + * Based on r8a7795-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#include <linux/bug.h> +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/pm.h> +#include <linux/slab.h> +#include <linux/soc/renesas/rcar-rst.h> + +#include <dt-bindings/clock/r8a779a0-cpg-mssr.h> + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum rcar_r8a779a0_clk_types { + CLK_TYPE_R8A779A0_MAIN = CLK_TYPE_CUSTOM, + CLK_TYPE_R8A779A0_PLL1, + CLK_TYPE_R8A779A0_PLL2X_3X, /* PLL[23][01] */ + CLK_TYPE_R8A779A0_PLL5, + CLK_TYPE_R8A779A0_MDSEL, /* Select parent/divider using mode pin */ + CLK_TYPE_R8A779A0_OSC, /* OSC EXTAL predivider and fixed divider */ +}; + +struct rcar_r8a779a0_cpg_pll_config { + u8 extal_div; + u8 pll1_mult; + u8 pll1_div; + u8 pll5_mult; + u8 pll5_div; + u8 osc_prediv; +}; + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A779A0_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL1, + CLK_PLL20, + CLK_PLL21, + CLK_PLL30, + CLK_PLL31, + CLK_PLL5, + CLK_PLL1_DIV2, + CLK_PLL20_DIV2, + CLK_PLL21_DIV2, + CLK_PLL30_DIV2, + CLK_PLL31_DIV2, + CLK_PLL5_DIV2, + CLK_PLL5_DIV4, + CLK_S1, + CLK_S2, + CLK_S3, + CLK_SDSRC, + CLK_RPCSRC, + CLK_OCO, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +#define DEF_PLL(_name, _id, _offset) \ + DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \ + .offset = _offset) + +static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_R8A779A0_MAIN, CLK_EXTAL), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_R8A779A0_PLL1, CLK_MAIN), + DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_R8A779A0_PLL5, CLK_MAIN), + DEF_PLL(".pll20", CLK_PLL20, 0x0834), + DEF_PLL(".pll21", CLK_PLL21, 0x0838), + DEF_PLL(".pll30", CLK_PLL30, 0x083c), + DEF_PLL(".pll31", CLK_PLL31, 0x0840), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".pll20_div2", CLK_PLL20_DIV2, CLK_PLL20, 2, 1), + DEF_FIXED(".pll21_div2", CLK_PLL21_DIV2, CLK_PLL21, 2, 1), + DEF_FIXED(".pll30_div2", CLK_PLL30_DIV2, CLK_PLL30, 2, 1), + DEF_FIXED(".pll31_div2", CLK_PLL31_DIV2, CLK_PLL31, 2, 1), + DEF_FIXED(".pll5_div2", CLK_PLL5_DIV2, CLK_PLL5, 2, 1), + DEF_FIXED(".pll5_div4", CLK_PLL5_DIV4, CLK_PLL5_DIV2, 2, 1), + DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 4, 1), + DEF_RATE(".oco", CLK_OCO, 32768), + + /* Core Clock Outputs */ + DEF_FIXED("zx", R8A779A0_CLK_ZX, CLK_PLL20_DIV2, 2, 1), + DEF_FIXED("s1d1", R8A779A0_CLK_S1D1, CLK_S1, 1, 1), + DEF_FIXED("s1d2", R8A779A0_CLK_S1D2, CLK_S1, 2, 1), + DEF_FIXED("s1d4", R8A779A0_CLK_S1D4, CLK_S1, 4, 1), + DEF_FIXED("s1d8", R8A779A0_CLK_S1D8, CLK_S1, 8, 1), + DEF_FIXED("s1d12", R8A779A0_CLK_S1D12, CLK_S1, 12, 1), + DEF_FIXED("s3d1", R8A779A0_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d2", R8A779A0_CLK_S3D2, CLK_S3, 2, 1), + DEF_FIXED("s3d4", R8A779A0_CLK_S3D4, CLK_S3, 4, 1), + DEF_FIXED("zs", R8A779A0_CLK_ZS, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("zt", R8A779A0_CLK_ZT, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED("ztr", R8A779A0_CLK_ZTR, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED("zr", R8A779A0_CLK_ZR, CLK_PLL1_DIV2, 1, 1), + DEF_FIXED("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, 1, 1), + DEF_FIXED("cnndsp", R8A779A0_CLK_CNNDSP, CLK_PLL5_DIV4, 1, 1), + DEF_FIXED("vip", R8A779A0_CLK_VIP, CLK_PLL5, 5, 1), + DEF_FIXED("adgh", R8A779A0_CLK_ADGH, CLK_PLL5_DIV4, 1, 1), + DEF_FIXED("icu", R8A779A0_CLK_ICU, CLK_PLL5_DIV4, 2, 1), + DEF_FIXED("icud2", R8A779A0_CLK_ICUD2, CLK_PLL5_DIV4, 4, 1), + DEF_FIXED("vcbus", R8A779A0_CLK_VCBUS, CLK_PLL5_DIV4, 1, 1), + DEF_FIXED("cbfusa", R8A779A0_CLK_CBFUSA, CLK_MAIN, 2, 1), + + DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), + DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880), + + DEF_GEN3_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8), + DEF_GEN3_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), +}; + +static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { + DEF_MOD("scif0", 702, R8A779A0_CLK_S1D8), + DEF_MOD("scif1", 703, R8A779A0_CLK_S1D8), + DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8), + DEF_MOD("scif4", 705, R8A779A0_CLK_S1D8), +}; + +static spinlock_t cpg_lock; + +static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata; +static unsigned int cpg_clk_extalr __initdata; +static u32 cpg_mode __initdata; + +struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, + const struct cpg_core_clk *core, const struct cpg_mssr_info *info, + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers) +{ + const struct clk *parent; + unsigned int mult = 1; + unsigned int div = 1; + u32 value; + + parent = clks[core->parent & 0xffff]; /* some types use high bits */ + if (IS_ERR(parent)) + return ERR_CAST(parent); + + switch (core->type) { + case CLK_TYPE_R8A779A0_MAIN: + div = cpg_pll_config->extal_div; + break; + + case CLK_TYPE_R8A779A0_PLL1: + mult = cpg_pll_config->pll1_mult; + div = cpg_pll_config->pll1_div; + break; + + case CLK_TYPE_R8A779A0_PLL2X_3X: + value = readl(base + core->offset); + mult = (((value >> 24) & 0x7f) + 1) * 2; + break; + + case CLK_TYPE_R8A779A0_PLL5: + mult = cpg_pll_config->pll5_mult; + div = cpg_pll_config->pll5_div; + break; + + case CLK_TYPE_R8A779A0_MDSEL: + /* + * Clock selectable between two parents and two fixed dividers + * using a mode pin + */ + if (cpg_mode & BIT(core->offset)) { + div = core->div & 0xffff; + } else { + parent = clks[core->parent >> 16]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + div = core->div >> 16; + } + mult = 1; + break; + + case CLK_TYPE_R8A779A0_OSC: + /* + * Clock combining OSC EXTAL predivider and a fixed divider + */ + div = cpg_pll_config->osc_prediv * core->div; + break; + + default: + return ERR_PTR(-EINVAL); + } + + return clk_register_fixed_factor(NULL, core->name, + __clk_get_name(parent), 0, mult, div); +} + +/* + * CPG Clock Data + */ +/* + * MD EXTAL PLL1 PLL20 PLL30 PLL4 PLL5 OSC + * 14 13 (MHz) 21 31 + * -------------------------------------------------------- + * 0 0 16.66 x 1 x128 x216 x128 x144 x192 /16 + * 0 1 20 x 1 x106 x180 x106 x120 x160 /19 + * 1 0 Prohibited setting + * 1 1 33.33 / 2 x128 x216 x128 x144 x192 /32 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ + (((md) & BIT(13)) >> 13)) + +static const struct rcar_r8a779a0_cpg_pll_config cpg_pll_configs[4] = { + /* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */ + { 1, 128, 1, 192, 1, 16, }, + { 1, 106, 1, 160, 1, 19, }, + { 0, 0, 0, 0, 0, 0, }, + { 2, 128, 1, 192, 1, 32, }, +}; + +static int __init r8a779a0_cpg_mssr_init(struct device *dev) +{ + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + cpg_clk_extalr = CLK_EXTALR; + spin_lock_init(&cpg_lock); + + return 0; +} + +const struct cpg_mssr_info r8a779a0_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a779a0_core_clks, + .num_core_clks = ARRAY_SIZE(r8a779a0_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a779a0_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a779a0_mod_clks), + .num_hw_mod_clks = 15 * 32, + + /* Callbacks */ + .init = r8a779a0_cpg_mssr_init, + .cpg_clk_register = rcar_r8a779a0_cpg_clk_register, + + .reg_layout = CLK_REG_LAYOUT_RCAR_V3U, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 5a306d28738c..94db88370337 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -57,8 +57,10 @@ static const u16 mstpsr[] = { 0x9A0, 0x9A4, 0x9A8, 0x9AC, }; -#define MSTPSR(i) mstpsr[i] - +static const u16 mstpsr_for_v3u[] = { + 0x2E00, 0x2E04, 0x2E08, 0x2E0C, 0x2E10, 0x2E14, 0x2E18, 0x2E1C, + 0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38, +}; /* * System Module Stop Control Register offsets @@ -69,7 +71,10 @@ static const u16 smstpcr[] = { 0x990, 0x994, 0x998, 0x99C, }; -#define SMSTPCR(i) smstpcr[i] +static const u16 mstpcr_for_v3u[] = { + 0x2D00, 0x2D04, 0x2D08, 0x2D0C, 0x2D10, 0x2D14, 0x2D18, 0x2D1C, + 0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38, +}; /* * Standby Control Register offsets (RZ/A) @@ -81,8 +86,6 @@ static const u16 stbcr[] = { 0x424, 0x428, 0x42C, }; -#define STBCR(i) stbcr[i] - /* * Software Reset Register offsets */ @@ -92,8 +95,10 @@ static const u16 srcr[] = { 0x920, 0x924, 0x928, 0x92C, }; -#define SRCR(i) srcr[i] - +static const u16 srcr_for_v3u[] = { + 0x2C00, 0x2C04, 0x2C08, 0x2C0C, 0x2C10, 0x2C14, 0x2C18, 0x2C1C, + 0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38, +}; /* Realtime Module Stop Control Register offsets */ #define RMSTPCR(i) (smstpcr[i] - 0x20) @@ -102,8 +107,16 @@ static const u16 srcr[] = { #define MMSTPCR(i) (smstpcr[i] + 0x20) /* Software Reset Clearing Register offsets */ -#define SRSTCLR(i) (0x940 + (i) * 4) +static const u16 srstclr[] = { + 0x940, 0x944, 0x948, 0x94C, 0x950, 0x954, 0x958, 0x95C, + 0x960, 0x964, 0x968, 0x96C, +}; + +static const u16 srstclr_for_v3u[] = { + 0x2C80, 0x2C84, 0x2C88, 0x2C8C, 0x2C90, 0x2C94, 0x2C98, 0x2C9C, + 0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8, +}; /** * Clock Pulse Generator / Module Standby and Software Reset Private Data @@ -111,13 +124,17 @@ static const u16 srcr[] = { * @rcdev: Optional reset controller entity * @dev: CPG/MSSR device * @base: CPG/MSSR register block base address + * @reg_layout: CPG/MSSR register layout * @rmw_lock: protects RMW register accesses * @np: Device node in DT for this CPG/MSSR module * @num_core_clks: Number of Core Clocks in clks[] * @num_mod_clks: Number of Module Clocks in clks[] * @last_dt_core_clk: ID of the last Core Clock exported to DT - * @stbyctrl: This device has Standby Control Registers * @notifiers: Notifier chain to save/restore clock state for system resume + * @status_regs: Pointer to status registers array + * @control_regs: Pointer to control registers array + * @reset_regs: Pointer to reset registers array + * @reset_clear_regs: Pointer to reset clearing registers array * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control * @smstpcr_saved[].val: Saved values of SMSTPCR[] * @clks: Array containing all Core and Module Clocks @@ -128,19 +145,23 @@ struct cpg_mssr_priv { #endif struct device *dev; void __iomem *base; + enum clk_reg_layout reg_layout; spinlock_t rmw_lock; struct device_node *np; unsigned int num_core_clks; unsigned int num_mod_clks; unsigned int last_dt_core_clk; - bool stbyctrl; struct raw_notifier_head notifiers; + const u16 *status_regs; + const u16 *control_regs; + const u16 *reset_regs; + const u16 *reset_clear_regs; struct { u32 mask; u32 val; - } smstpcr_saved[ARRAY_SIZE(smstpcr)]; + } smstpcr_saved[ARRAY_SIZE(mstpsr_for_v3u)]; struct clk *clks[]; }; @@ -177,40 +198,40 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) enable ? "ON" : "OFF"); spin_lock_irqsave(&priv->rmw_lock, flags); - if (priv->stbyctrl) { - value = readb(priv->base + STBCR(reg)); + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) { + value = readb(priv->base + priv->control_regs[reg]); if (enable) value &= ~bitmask; else value |= bitmask; - writeb(value, priv->base + STBCR(reg)); + writeb(value, priv->base + priv->control_regs[reg]); /* dummy read to ensure write has completed */ - readb(priv->base + STBCR(reg)); - barrier_data(priv->base + STBCR(reg)); + readb(priv->base + priv->control_regs[reg]); + barrier_data(priv->base + priv->control_regs[reg]); } else { - value = readl(priv->base + SMSTPCR(reg)); + value = readl(priv->base + priv->control_regs[reg]); if (enable) value &= ~bitmask; else value |= bitmask; - writel(value, priv->base + SMSTPCR(reg)); + writel(value, priv->base + priv->control_regs[reg]); } spin_unlock_irqrestore(&priv->rmw_lock, flags); - if (!enable || priv->stbyctrl) + if (!enable || priv->reg_layout == CLK_REG_LAYOUT_RZ_A) return 0; for (i = 1000; i > 0; --i) { - if (!(readl(priv->base + MSTPSR(reg)) & bitmask)) + if (!(readl(priv->base + priv->status_regs[reg]) & bitmask)) break; cpu_relax(); } if (!i) { dev_err(dev, "Failed to enable SMSTP %p[%d]\n", - priv->base + SMSTPCR(reg), bit); + priv->base + priv->control_regs[reg], bit); return -ETIMEDOUT; } @@ -233,10 +254,10 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) struct cpg_mssr_priv *priv = clock->priv; u32 value; - if (priv->stbyctrl) - value = readb(priv->base + STBCR(clock->index / 32)); + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) + value = readb(priv->base + priv->control_regs[clock->index / 32]); else - value = readl(priv->base + MSTPSR(clock->index / 32)); + value = readl(priv->base + priv->status_regs[clock->index / 32]); return !(value & BIT(clock->index % 32)); } @@ -272,7 +293,7 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec, case CPG_MOD: type = "module"; - if (priv->stbyctrl) { + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) { idx = MOD_CLK_PACK_10(clkidx); range_check = 7 - (clkidx % 10); } else { @@ -578,13 +599,13 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev, dev_dbg(priv->dev, "reset %u%02u\n", reg, bit); /* Reset module */ - writel(bitmask, priv->base + SRCR(reg)); + writel(bitmask, priv->base + priv->reset_regs[reg]); /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ udelay(35); /* Release module from reset state */ - writel(bitmask, priv->base + SRSTCLR(reg)); + writel(bitmask, priv->base + priv->reset_clear_regs[reg]); return 0; } @@ -598,7 +619,7 @@ static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id) dev_dbg(priv->dev, "assert %u%02u\n", reg, bit); - writel(bitmask, priv->base + SRCR(reg)); + writel(bitmask, priv->base + priv->reset_regs[reg]); return 0; } @@ -612,7 +633,7 @@ static int cpg_mssr_deassert(struct reset_controller_dev *rcdev, dev_dbg(priv->dev, "deassert %u%02u\n", reg, bit); - writel(bitmask, priv->base + SRSTCLR(reg)); + writel(bitmask, priv->base + priv->reset_clear_regs[reg]); return 0; } @@ -624,7 +645,7 @@ static int cpg_mssr_status(struct reset_controller_dev *rcdev, unsigned int bit = id % 32; u32 bitmask = BIT(bit); - return !!(readl(priv->base + SRCR(reg)) & bitmask); + return !!(readl(priv->base + priv->reset_regs[reg]) & bitmask); } static const struct reset_control_ops cpg_mssr_reset_ops = { @@ -804,6 +825,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a77995_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R8A779A0 + { + .compatible = "renesas,r8a779a0-cpg-mssr", + .data = &r8a779a0_cpg_mssr_info, + }, +#endif { /* sentinel */ } }; @@ -825,9 +852,10 @@ static int cpg_mssr_suspend_noirq(struct device *dev) /* Save module registers with bits under our control */ for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { if (priv->smstpcr_saved[reg].mask) - priv->smstpcr_saved[reg].val = priv->stbyctrl ? - readb(priv->base + STBCR(reg)) : - readl(priv->base + SMSTPCR(reg)); + priv->smstpcr_saved[reg].val = + priv->reg_layout == CLK_REG_LAYOUT_RZ_A ? + readb(priv->base + priv->control_regs[reg]) : + readl(priv->base + priv->control_regs[reg]); } /* Save core clocks */ @@ -855,23 +883,23 @@ static int cpg_mssr_resume_noirq(struct device *dev) if (!mask) continue; - if (priv->stbyctrl) - oldval = readb(priv->base + STBCR(reg)); + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) + oldval = readb(priv->base + priv->control_regs[reg]); else - oldval = readl(priv->base + SMSTPCR(reg)); + oldval = readl(priv->base + priv->control_regs[reg]); newval = oldval & ~mask; newval |= priv->smstpcr_saved[reg].val & mask; if (newval == oldval) continue; - if (priv->stbyctrl) { - writeb(newval, priv->base + STBCR(reg)); + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) { + writeb(newval, priv->base + priv->control_regs[reg]); /* dummy read to ensure write has completed */ - readb(priv->base + STBCR(reg)); - barrier_data(priv->base + STBCR(reg)); + readb(priv->base + priv->control_regs[reg]); + barrier_data(priv->base + priv->control_regs[reg]); continue; } else - writel(newval, priv->base + SMSTPCR(reg)); + writel(newval, priv->base + priv->control_regs[reg]); /* Wait until enabled clocks are really enabled */ mask &= ~priv->smstpcr_saved[reg].val; @@ -879,7 +907,7 @@ static int cpg_mssr_resume_noirq(struct device *dev) continue; for (i = 1000; i > 0; --i) { - oldval = readl(priv->base + MSTPSR(reg)); + oldval = readl(priv->base + priv->status_regs[reg]); if (!(oldval & mask)) break; cpu_relax(); @@ -887,8 +915,8 @@ static int cpg_mssr_resume_noirq(struct device *dev) if (!i) dev_warn(dev, "Failed to enable %s%u[0x%x]\n", - priv->stbyctrl ? "STB" : "SMSTP", reg, - oldval & mask); + priv->reg_layout == CLK_REG_LAYOUT_RZ_A ? + "STB" : "SMSTP", reg, oldval & mask); } return 0; @@ -937,7 +965,23 @@ static int __init cpg_mssr_common_init(struct device *dev, priv->num_mod_clks = info->num_hw_mod_clks; priv->last_dt_core_clk = info->last_dt_core_clk; RAW_INIT_NOTIFIER_HEAD(&priv->notifiers); - priv->stbyctrl = info->stbyctrl; + priv->reg_layout = info->reg_layout; + if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) { + priv->status_regs = mstpsr; + priv->control_regs = smstpcr; + priv->reset_regs = srcr; + priv->reset_clear_regs = srstclr; + } else if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) { + priv->control_regs = stbcr; + } else if (priv->reg_layout == CLK_REG_LAYOUT_RCAR_V3U) { + priv->status_regs = mstpsr_for_v3u; + priv->control_regs = mstpcr_for_v3u; + priv->reset_regs = srcr_for_v3u; + priv->reset_clear_regs = srstclr_for_v3u; + } else { + error = -EINVAL; + goto out_err; + } for (i = 0; i < nclks; i++) priv->clks[i] = ERR_PTR(-ENOENT); @@ -1015,7 +1059,7 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) return error; /* Reset Controller not supported for Standby Control SoCs */ - if (info->stbyctrl) + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) return 0; error = cpg_mssr_reset_controller_register(priv); diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 1cc569484250..6b2a0ade482e 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -85,6 +85,12 @@ struct mssr_mod_clk { struct device_node; +enum clk_reg_layout { + CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3 = 0, + CLK_REG_LAYOUT_RZ_A, + CLK_REG_LAYOUT_RCAR_V3U, +}; + /** * SoC-specific CPG/MSSR Description * @@ -105,6 +111,7 @@ struct device_node; * @crit_mod_clks: Array with Module Clock IDs of critical clocks that * should not be disabled without a knowledgeable driver * @num_crit_mod_clks: Number of entries in crit_mod_clks[] + * @reg_layout: CPG/MSSR register layout from enum clk_reg_layout * * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power * Management, in addition to Module Clocks @@ -112,10 +119,6 @@ struct device_node; * * @init: Optional callback to perform SoC-specific initialization * @cpg_clk_register: Optional callback to handle special Core Clock types - * - * @stbyctrl: This device has Standby Control Registers which are 8-bits - * wide, no status registers (MSTPSR) and have different address - * offsets. */ struct cpg_mssr_info { @@ -130,7 +133,7 @@ struct cpg_mssr_info { unsigned int num_core_clks; unsigned int last_dt_core_clk; unsigned int num_total_core_clks; - bool stbyctrl; + enum clk_reg_layout reg_layout; /* Module Clocks */ const struct mssr_mod_clk *mod_clks; @@ -174,6 +177,7 @@ extern const struct cpg_mssr_info r8a77970_cpg_mssr_info; extern const struct cpg_mssr_info r8a77980_cpg_mssr_info; extern const struct cpg_mssr_info r8a77990_cpg_mssr_info; extern const struct cpg_mssr_info r8a77995_cpg_mssr_info; +extern const struct cpg_mssr_info r8a779a0_cpg_mssr_info; void __init cpg_mssr_early_init(struct device_node *np, const struct cpg_mssr_info *info); diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig new file mode 100644 index 000000000000..47cd6c5de837 --- /dev/null +++ b/drivers/clk/rockchip/Kconfig @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: GPL-2.0 +# common clock support for ROCKCHIP SoC family. + +config COMMON_CLK_ROCKCHIP + bool "Rockchip clock controller common support" + depends on ARCH_ROCKCHIP + default ARCH_ROCKCHIP + help + Say y here to enable common clock controller for Rockchip platforms. + +if COMMON_CLK_ROCKCHIP +config CLK_PX30 + bool "Rockchip PX30 clock controller support" + default y + help + Build the driver for PX30 Clock Driver. + +config CLK_RV110X + bool "Rockchip RV110x clock controller support" + default y + help + Build the driver for RV110x Clock Driver. + +config CLK_RK3036 + bool "Rockchip RK3036 clock controller support" + default y + help + Build the driver for RK3036 Clock Driver. + +config CLK_RK312X + bool "Rockchip RK312x clock controller support" + default y + help + Build the driver for RK312x Clock Driver. + +config CLK_RK3188 + bool "Rockchip RK3188 clock controller support" + default y + help + Build the driver for RK3188 Clock Driver. + +config CLK_RK322X + bool "Rockchip RK322x clock controller support" + default y + help + Build the driver for RK322x Clock Driver. + +config CLK_RK3288 + bool "Rockchip RK3288 clock controller support" + depends on ARM + default y + help + Build the driver for RK3288 Clock Driver. + +config CLK_RK3308 + bool "Rockchip RK3308 clock controller support" + default y + help + Build the driver for RK3308 Clock Driver. + +config CLK_RK3328 + bool "Rockchip RK3328 clock controller support" + default y + help + Build the driver for RK3328 Clock Driver. + +config CLK_RK3368 + bool "Rockchip RK3368 clock controller support" + default y + help + Build the driver for RK3368 Clock Driver. + +config CLK_RK3399 + tristate "Rockchip RK3399 clock controller support" + default y + help + Build the driver for RK3399 Clock Driver. +endif diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 7c5b5813a87c..a99e4d9bbae1 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -3,24 +3,26 @@ # Rockchip Clock specific Makefile # -obj-y += clk.o -obj-y += clk-pll.o -obj-y += clk-cpu.o -obj-y += clk-half-divider.o -obj-y += clk-inverter.o -obj-y += clk-mmc-phase.o -obj-y += clk-muxgrf.o -obj-y += clk-ddr.o -obj-$(CONFIG_RESET_CONTROLLER) += softrst.o +obj-$(CONFIG_COMMON_CLK_ROCKCHIP) += clk-rockchip.o -obj-y += clk-px30.o -obj-y += clk-rv1108.o -obj-y += clk-rk3036.o -obj-y += clk-rk3128.o -obj-y += clk-rk3188.o -obj-y += clk-rk3228.o -obj-y += clk-rk3288.o -obj-y += clk-rk3308.o -obj-y += clk-rk3328.o -obj-y += clk-rk3368.o -obj-y += clk-rk3399.o +clk-rockchip-y += clk.o +clk-rockchip-y += clk-pll.o +clk-rockchip-y += clk-cpu.o +clk-rockchip-y += clk-half-divider.o +clk-rockchip-y += clk-inverter.o +clk-rockchip-y += clk-mmc-phase.o +clk-rockchip-y += clk-muxgrf.o +clk-rockchip-y += clk-ddr.o +clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o + +obj-$(CONFIG_CLK_PX30) += clk-px30.o +obj-$(CONFIG_CLK_RV110X) += clk-rv1108.o +obj-$(CONFIG_CLK_RK3036) += clk-rk3036.o +obj-$(CONFIG_CLK_RK312X) += clk-rk3128.o +obj-$(CONFIG_CLK_RK3188) += clk-rk3188.o +obj-$(CONFIG_CLK_RK322X) += clk-rk3228.o +obj-$(CONFIG_CLK_RK3288) += clk-rk3288.o +obj-$(CONFIG_CLK_RK3308) += clk-rk3308.o +obj-$(CONFIG_CLK_RK3328) += clk-rk3328.o +obj-$(CONFIG_CLK_RK3368) += clk-rk3368.o +obj-$(CONFIG_CLK_RK3399) += clk-rk3399.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c index 9273bce4d7b6..86718c54e56b 100644 --- a/drivers/clk/rockchip/clk-ddr.c +++ b/drivers/clk/rockchip/clk-ddr.c @@ -136,3 +136,4 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, return clk; } +EXPORT_SYMBOL_GPL(rockchip_clk_register_ddrclk); diff --git a/drivers/clk/rockchip/clk-half-divider.c b/drivers/clk/rockchip/clk-half-divider.c index b333fc28c94b..ccd5c270c213 100644 --- a/drivers/clk/rockchip/clk-half-divider.c +++ b/drivers/clk/rockchip/clk-half-divider.c @@ -166,7 +166,7 @@ struct clk *rockchip_clk_register_halfdiv(const char *name, unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk_hw *hw = ERR_PTR(-ENOMEM); struct clk_mux *mux = NULL; struct clk_gate *gate = NULL; struct clk_divider *div = NULL; @@ -212,16 +212,18 @@ struct clk *rockchip_clk_register_halfdiv(const char *name, div_ops = &clk_half_divider_ops; } - clk = clk_register_composite(NULL, name, parent_names, num_parents, - mux ? &mux->hw : NULL, mux_ops, - div ? &div->hw : NULL, div_ops, - gate ? &gate->hw : NULL, gate_ops, - flags); + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags); + if (IS_ERR(hw)) + goto err_div; - return clk; + return hw->clk; err_div: kfree(gate); err_gate: kfree(mux); - return ERR_PTR(-ENOMEM); + return ERR_CAST(hw); } diff --git a/drivers/clk/rockchip/clk-rk3308.c b/drivers/clk/rockchip/clk-rk3308.c index b0baf87a283e..5bf15f2a44b7 100644 --- a/drivers/clk/rockchip/clk-rk3308.c +++ b/drivers/clk/rockchip/clk-rk3308.c @@ -133,7 +133,6 @@ PNAME(mux_uart1_p) = { "clk_uart1_src", "dummy", "clk_uart1_frac" }; PNAME(mux_uart2_p) = { "clk_uart2_src", "dummy", "clk_uart2_frac" }; PNAME(mux_uart3_p) = { "clk_uart3_src", "dummy", "clk_uart3_frac" }; PNAME(mux_uart4_p) = { "clk_uart4_src", "dummy", "clk_uart4_frac" }; -PNAME(mux_timer_src_p) = { "xin24m", "clk_rtc32k" }; PNAME(mux_dclk_vop_p) = { "dclk_vop_src", "dclk_vop_frac", "xin24m" }; PNAME(mux_nandc_p) = { "clk_nandc_div", "clk_nandc_div50" }; PNAME(mux_sdmmc_p) = { "clk_sdmmc_div", "clk_sdmmc_div50" }; diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index ce1d2446f142..7df2f1e00347 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -5,9 +5,11 @@ */ #include <linux/clk-provider.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <dt-bindings/clock/rk3399-cru.h> @@ -1600,3 +1602,57 @@ static void __init rk3399_pmu_clk_init(struct device_node *np) rockchip_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(rk3399_cru_pmu, "rockchip,rk3399-pmucru", rk3399_pmu_clk_init); + +struct clk_rk3399_inits { + void (*inits)(struct device_node *np); +}; + +static const struct clk_rk3399_inits clk_rk3399_pmucru_init = { + .inits = rk3399_pmu_clk_init, +}; + +static const struct clk_rk3399_inits clk_rk3399_cru_init = { + .inits = rk3399_clk_init, +}; + +static const struct of_device_id clk_rk3399_match_table[] = { + { + .compatible = "rockchip,rk3399-cru", + .data = &clk_rk3399_cru_init, + }, { + .compatible = "rockchip,rk3399-pmucru", + .data = &clk_rk3399_pmucru_init, + }, + { } +}; +MODULE_DEVICE_TABLE(of, clk_rk3399_match_table); + +static int __init clk_rk3399_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct clk_rk3399_inits *init_data; + + match = of_match_device(clk_rk3399_match_table, &pdev->dev); + if (!match || !match->data) + return -EINVAL; + + init_data = match->data; + if (init_data->inits) + init_data->inits(np); + + return 0; +} + +static struct platform_driver clk_rk3399_driver = { + .driver = { + .name = "clk-rk3399", + .of_match_table = clk_rk3399_match_table, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(clk_rk3399_driver, clk_rk3399_probe); + +MODULE_DESCRIPTION("Rockchip RK3399 Clock Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:clk-rk3399"); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 546e810c3560..b443169dd408 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -43,7 +43,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, u8 gate_shift, u8 gate_flags, unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk_hw *hw; struct clk_mux *mux = NULL; struct clk_gate *gate = NULL; struct clk_divider *div = NULL; @@ -100,20 +100,18 @@ static struct clk *rockchip_clk_register_branch(const char *name, : &clk_divider_ops; } - clk = clk_register_composite(NULL, name, parent_names, num_parents, - mux ? &mux->hw : NULL, mux_ops, - div ? &div->hw : NULL, div_ops, - gate ? &gate->hw : NULL, gate_ops, - flags); - - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto err_composite; + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags); + if (IS_ERR(hw)) { + kfree(div); + kfree(gate); + return ERR_CAST(hw); } - return clk; -err_composite: - kfree(div); + return hw->clk; err_div: kfree(gate); err_gate: @@ -214,8 +212,8 @@ static struct clk *rockchip_clk_register_frac_branch( unsigned long flags, struct rockchip_clk_branch *child, spinlock_t *lock) { + struct clk_hw *hw; struct rockchip_clk_frac *frac; - struct clk *clk; struct clk_gate *gate = NULL; struct clk_fractional_divider *div = NULL; const struct clk_ops *div_ops = NULL, *gate_ops = NULL; @@ -255,14 +253,14 @@ static struct clk *rockchip_clk_register_frac_branch( div->approximation = rockchip_fractional_approximation; div_ops = &clk_fractional_divider_ops; - clk = clk_register_composite(NULL, name, parent_names, num_parents, - NULL, NULL, - &div->hw, div_ops, - gate ? &gate->hw : NULL, gate_ops, - flags | CLK_SET_RATE_UNGATE); - if (IS_ERR(clk)) { + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + NULL, NULL, + &div->hw, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags | CLK_SET_RATE_UNGATE); + if (IS_ERR(hw)) { kfree(frac); - return clk; + return ERR_CAST(hw); } if (child) { @@ -292,7 +290,7 @@ static struct clk *rockchip_clk_register_frac_branch( mux_clk = clk_register(NULL, &frac_mux->hw); if (IS_ERR(mux_clk)) { kfree(frac); - return clk; + return mux_clk; } rockchip_clk_add_lookup(ctx, mux_clk, child->id); @@ -301,7 +299,7 @@ static struct clk *rockchip_clk_register_frac_branch( if (frac->mux_frac_idx >= 0) { pr_debug("%s: found fractional parent in mux at pos %d\n", __func__, frac->mux_frac_idx); - ret = clk_notifier_register(clk, &frac->clk_nb); + ret = clk_notifier_register(hw->clk, &frac->clk_nb); if (ret) pr_err("%s: failed to register clock notifier for %s\n", __func__, name); @@ -311,7 +309,7 @@ static struct clk *rockchip_clk_register_frac_branch( } } - return clk; + return hw->clk; } static struct clk *rockchip_clk_register_factor_branch(const char *name, @@ -320,7 +318,7 @@ static struct clk *rockchip_clk_register_factor_branch(const char *name, int gate_offset, u8 gate_shift, u8 gate_flags, unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk_hw *hw; struct clk_gate *gate = NULL; struct clk_fixed_factor *fix = NULL; @@ -349,20 +347,22 @@ static struct clk *rockchip_clk_register_factor_branch(const char *name, fix->mult = mult; fix->div = div; - clk = clk_register_composite(NULL, name, parent_names, num_parents, - NULL, NULL, - &fix->hw, &clk_fixed_factor_ops, - &gate->hw, &clk_gate_ops, flags); - if (IS_ERR(clk)) { + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + NULL, NULL, + &fix->hw, &clk_fixed_factor_ops, + &gate->hw, &clk_gate_ops, flags); + if (IS_ERR(hw)) { kfree(fix); kfree(gate); + return ERR_CAST(hw); } - return clk; + return hw->clk; } -struct rockchip_clk_provider * __init rockchip_clk_init(struct device_node *np, - void __iomem *base, unsigned long nr_clks) +struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, + void __iomem *base, + unsigned long nr_clks) { struct rockchip_clk_provider *ctx; struct clk **clk_table; @@ -394,14 +394,16 @@ err_free: kfree(ctx); return ERR_PTR(-ENOMEM); } +EXPORT_SYMBOL_GPL(rockchip_clk_init); -void __init rockchip_clk_of_add_provider(struct device_node *np, - struct rockchip_clk_provider *ctx) +void rockchip_clk_of_add_provider(struct device_node *np, + struct rockchip_clk_provider *ctx) { if (of_clk_add_provider(np, of_clk_src_onecell_get, &ctx->clk_data)) pr_err("%s: could not register clk provider\n", __func__); } +EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider); void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, struct clk *clk, unsigned int id) @@ -409,8 +411,9 @@ void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, if (ctx->clk_data.clks && id) ctx->clk_data.clks[id] = clk; } +EXPORT_SYMBOL_GPL(rockchip_clk_add_lookup); -void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, +void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, struct rockchip_pll_clock *list, unsigned int nr_pll, int grf_lock_offset) { @@ -433,11 +436,11 @@ void __init rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, rockchip_clk_add_lookup(ctx, clk, list->id); } } +EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); -void __init rockchip_clk_register_branches( - struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk) +void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk) { struct clk *clk = NULL; unsigned int idx; @@ -566,14 +569,15 @@ void __init rockchip_clk_register_branches( rockchip_clk_add_lookup(ctx, clk, list->id); } } - -void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, - unsigned int lookup_id, - const char *name, const char *const *parent_names, - u8 num_parents, - const struct rockchip_cpuclk_reg_data *reg_data, - const struct rockchip_cpuclk_rate_table *rates, - int nrates) +EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); + +void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, + unsigned int lookup_id, + const char *name, const char *const *parent_names, + u8 num_parents, + const struct rockchip_cpuclk_reg_data *reg_data, + const struct rockchip_cpuclk_rate_table *rates, + int nrates) { struct clk *clk; @@ -588,9 +592,10 @@ void __init rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, rockchip_clk_add_lookup(ctx, clk, lookup_id); } +EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); -void __init rockchip_clk_protect_critical(const char *const clocks[], - int nclocks) +void rockchip_clk_protect_critical(const char *const clocks[], + int nclocks) { int i; @@ -602,6 +607,7 @@ void __init rockchip_clk_protect_critical(const char *const clocks[], clk_prepare_enable(clk); } } +EXPORT_SYMBOL_GPL(rockchip_clk_protect_critical); static void __iomem *rst_base; static unsigned int reg_restart; @@ -621,10 +627,10 @@ static struct notifier_block rockchip_restart_handler = { .priority = 128, }; -void __init +void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, - unsigned int reg, - void (*cb)(void)) + unsigned int reg, + void (*cb)(void)) { int ret; @@ -636,3 +642,4 @@ rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, pr_err("%s: cannot register restart handler, %d\n", __func__, ret); } +EXPORT_SYMBOL_GPL(rockchip_register_restart_notifier); diff --git a/drivers/clk/rockchip/softrst.c b/drivers/clk/rockchip/softrst.c index 5f1ff5e47c4f..5d07266745b8 100644 --- a/drivers/clk/rockchip/softrst.c +++ b/drivers/clk/rockchip/softrst.c @@ -77,9 +77,9 @@ static const struct reset_control_ops rockchip_softrst_ops = { .deassert = rockchip_softrst_deassert, }; -void __init rockchip_register_softrst(struct device_node *np, - unsigned int num_regs, - void __iomem *base, u8 flags) +void rockchip_register_softrst(struct device_node *np, + unsigned int num_regs, + void __iomem *base, u8 flags) { struct rockchip_softrst *softrst; int ret; @@ -107,3 +107,4 @@ void __init rockchip_register_softrst(struct device_node *np, kfree(softrst); } }; +EXPORT_SYMBOL_GPL(rockchip_register_softrst); diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index efc4fa61fbaf..00ef4d1b0888 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -401,26 +401,34 @@ static int exynos5433_cpuclk_notifier_cb(struct notifier_block *nb, /* helper function to register a CPU clock */ int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, - unsigned int lookup_id, const char *name, const char *parent, - const char *alt_parent, unsigned long offset, - const struct exynos_cpuclk_cfg_data *cfg, + unsigned int lookup_id, const char *name, + const struct clk_hw *parent, const struct clk_hw *alt_parent, + unsigned long offset, const struct exynos_cpuclk_cfg_data *cfg, unsigned long num_cfgs, unsigned long flags) { struct exynos_cpuclk *cpuclk; struct clk_init_data init; - struct clk *parent_clk; + const char *parent_name; int ret = 0; + if (IS_ERR(parent) || IS_ERR(alt_parent)) { + pr_err("%s: invalid parent clock(s)\n", __func__); + return -EINVAL; + } + cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); if (!cpuclk) return -ENOMEM; + parent_name = clk_hw_get_name(parent); + init.name = name; init.flags = CLK_SET_RATE_PARENT; - init.parent_names = &parent; + init.parent_names = &parent_name; init.num_parents = 1; init.ops = &exynos_cpuclk_clk_ops; + cpuclk->alt_parent = alt_parent; cpuclk->hw.init = &init; cpuclk->ctrl_base = ctx->reg_base + offset; cpuclk->lock = &ctx->lock; @@ -430,23 +438,8 @@ int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, else cpuclk->clk_nb.notifier_call = exynos_cpuclk_notifier_cb; - cpuclk->alt_parent = __clk_get_hw(__clk_lookup(alt_parent)); - if (!cpuclk->alt_parent) { - pr_err("%s: could not lookup alternate parent %s\n", - __func__, alt_parent); - ret = -EINVAL; - goto free_cpuclk; - } - - parent_clk = __clk_lookup(parent); - if (!parent_clk) { - pr_err("%s: could not lookup parent clock %s\n", - __func__, parent); - ret = -EINVAL; - goto free_cpuclk; - } - ret = clk_notifier_register(parent_clk, &cpuclk->clk_nb); + ret = clk_notifier_register(parent->clk, &cpuclk->clk_nb); if (ret) { pr_err("%s: failed to register clock notifier for %s\n", __func__, name); @@ -471,7 +464,7 @@ int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, free_cpuclk_data: kfree(cpuclk->cfg); unregister_clk_nb: - clk_notifier_unregister(parent_clk, &cpuclk->clk_nb); + clk_notifier_unregister(parent->clk, &cpuclk->clk_nb); free_cpuclk: kfree(cpuclk); return ret; diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h index ad38cc27f3df..af74686db9ef 100644 --- a/drivers/clk/samsung/clk-cpu.h +++ b/drivers/clk/samsung/clk-cpu.h @@ -46,7 +46,7 @@ struct exynos_cpuclk_cfg_data { */ struct exynos_cpuclk { struct clk_hw hw; - struct clk_hw *alt_parent; + const struct clk_hw *alt_parent; void __iomem *ctrl_base; spinlock_t *lock; const struct exynos_cpuclk_cfg_data *cfg; @@ -62,9 +62,9 @@ struct exynos_cpuclk { #define CLK_CPU_HAS_E5433_REGS_LAYOUT (1 << 2) }; -extern int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, +int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, unsigned int lookup_id, const char *name, - const char *parent, const char *alt_parent, + const struct clk_hw *parent, const struct clk_hw *alt_parent, unsigned long offset, const struct exynos_cpuclk_cfg_data *cfg, unsigned long num_cfgs, unsigned long flags); diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 17897c7a84d4..17df7f9755aa 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -808,14 +808,16 @@ static const struct exynos_cpuclk_cfg_data e3250_armclk_d[] __initconst = { static void __init exynos3250_cmu_init(struct device_node *np) { struct samsung_clk_provider *ctx; + struct clk_hw **hws; ctx = samsung_cmu_register_one(np, &cmu_info); if (!ctx) return; + hws = ctx->clk_data.hws; exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_core_p[0], mout_core_p[1], 0x14200, - e3250_armclk_d, ARRAY_SIZE(e3250_armclk_d), + hws[CLK_MOUT_APLL], hws[CLK_MOUT_MPLL_USER_C], + 0x14200, e3250_armclk_d, ARRAY_SIZE(e3250_armclk_d), CLK_CPU_HAS_DIV1); exynos3_core_down_clock(ctx->reg_base); diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 51564fc23c63..436fcd279951 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1233,6 +1233,8 @@ static void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc soc) { struct samsung_clk_provider *ctx; + struct clk_hw **hws; + exynos4_soc = soc; reg_base = of_iomap(np, 0); @@ -1240,6 +1242,7 @@ static void __init exynos4_clk_init(struct device_node *np, panic("%s: failed to map registers\n", __func__); ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos4_fixed_rate_ext_clks, ARRAY_SIZE(exynos4_fixed_rate_ext_clks), @@ -1302,7 +1305,7 @@ static void __init exynos4_clk_init(struct device_node *np, exynos4210_fixed_factor_clks, ARRAY_SIZE(exynos4210_fixed_factor_clks)); exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_core_p4210[0], mout_core_p4210[1], 0x14200, + hws[CLK_MOUT_APLL], hws[CLK_SCLK_MPLL], 0x14200, e4210_armclk_d, ARRAY_SIZE(e4210_armclk_d), CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); } else { @@ -1317,7 +1320,7 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4x12_fixed_factor_clks)); exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_core_p4x12[0], mout_core_p4x12[1], 0x14200, + hws[CLK_MOUT_APLL], hws[CLK_MOUT_MPLL_USER_C], 0x14200, e4412_armclk_d, ARRAY_SIZE(e4412_armclk_d), CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); } diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 931c70a4da19..06588fab408a 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -253,14 +253,14 @@ static const struct samsung_mux_clock exynos5250_mux_clks[] __initconst = { /* * CMU_CPU */ - MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, CLK_SET_RATE_PARENT, 0), MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1), /* * CMU_CORE */ - MUX(0, "mout_mpll", mout_mpll_p, SRC_CORE1, 8, 1), + MUX(CLK_MOUT_MPLL, "mout_mpll", mout_mpll_p, SRC_CORE1, 8, 1), /* * CMU_TOP @@ -782,6 +782,7 @@ static void __init exynos5250_clk_init(struct device_node *np) { struct samsung_clk_provider *ctx; unsigned int tmp; + struct clk_hw **hws; if (np) { reg_base = of_iomap(np, 0); @@ -792,6 +793,7 @@ static void __init exynos5250_clk_init(struct device_node *np) } ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), @@ -821,7 +823,7 @@ static void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_gate(ctx, exynos5250_gate_clks, ARRAY_SIZE(exynos5250_gate_clks)); exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_cpu_p[0], mout_cpu_p[1], 0x200, + hws[CLK_MOUT_APLL], hws[CLK_MOUT_MPLL], 0x200, exynos5250_armclk_d, ARRAY_SIZE(exynos5250_armclk_d), CLK_CPU_HAS_DIV1); diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index fea33399a632..3ccd4eabd2a6 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -596,13 +596,14 @@ static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = { static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = { MUX(0, "mout_user_pclk66_gpio", mout_user_pclk66_gpio_p, SRC_TOP7, 4, 1), - MUX(0, "mout_mspll_kfc", mout_mspll_cpu_p, SRC_TOP7, 8, 2), - MUX(0, "mout_mspll_cpu", mout_mspll_cpu_p, SRC_TOP7, 12, 2), - - MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + MUX(CLK_MOUT_MSPLL_KFC, "mout_mspll_kfc", mout_mspll_cpu_p, + SRC_TOP7, 8, 2), + MUX(CLK_MOUT_MSPLL_CPU, "mout_mspll_cpu", mout_mspll_cpu_p, + SRC_TOP7, 12, 2), + MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0), MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1), - MUX_F(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1, + MUX_F(CLK_MOUT_KPLL, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1, CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0), MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1), @@ -712,8 +713,8 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = { SRC_TOP12, 8, 1), MUX(0, "mout_sw_aclk266_g2d", mout_sw_aclk266_g2d_p, SRC_TOP12, 12, 1), - MUX_F(0, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, SRC_TOP12, 16, 1, - CLK_SET_RATE_PARENT, 0), + MUX_F(CLK_MOUT_SW_ACLK_G3D, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, + SRC_TOP12, 16, 1, CLK_SET_RATE_PARENT, 0), MUX(0, "mout_sw_aclk300_jpeg", mout_sw_aclk300_jpeg_p, SRC_TOP12, 20, 1), MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1", @@ -1560,6 +1561,7 @@ static void __init exynos5x_clk_init(struct device_node *np, enum exynos5x_soc soc) { struct samsung_clk_provider *ctx; + struct clk_hw **hws; if (np) { reg_base = of_iomap(np, 0); @@ -1572,6 +1574,7 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5x_soc = soc; ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos5x_fixed_rate_ext_clks, ARRAY_SIZE(exynos5x_fixed_rate_ext_clks), @@ -1623,15 +1626,15 @@ static void __init exynos5x_clk_init(struct device_node *np, if (soc == EXYNOS5420) { exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_cpu_p[0], mout_cpu_p[1], 0x200, + hws[CLK_MOUT_APLL], hws[CLK_MOUT_MSPLL_CPU], 0x200, exynos5420_eglclk_d, ARRAY_SIZE(exynos5420_eglclk_d), 0); } else { exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_cpu_p[0], mout_cpu_p[1], 0x200, + hws[CLK_MOUT_APLL], hws[CLK_MOUT_MSPLL_CPU], 0x200, exynos5800_eglclk_d, ARRAY_SIZE(exynos5800_eglclk_d), 0); } exynos_register_cpu_clock(ctx, CLK_KFC_CLK, "kfcclk", - mout_kfc_p[0], mout_kfc_p[1], 0x28200, + hws[CLK_MOUT_KPLL], hws[CLK_MOUT_MSPLL_KFC], 0x28200, exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0); samsung_clk_extended_sleep_init(reg_base, @@ -1654,7 +1657,12 @@ static void __init exynos5x_clk_init(struct device_node *np, * that the internal busses get their clock regardless of the * main G3D clock enablement status. */ - clk_prepare_enable(__clk_lookup("mout_sw_aclk_g3d")); + clk_prepare_enable(hws[CLK_MOUT_SW_ACLK_G3D]->clk); + /* + * Keep top BPLL mux enabled permanently to ensure that DRAM operates + * properly. + */ + clk_prepare_enable(hws[CLK_MOUT_BPLL]->clk); samsung_clk_of_add_provider(np, ctx); } diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 6f29ecd0442e..f203074d858b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3679,6 +3679,7 @@ static void __init exynos5433_cmu_apollo_init(struct device_node *np) { void __iomem *reg_base; struct samsung_clk_provider *ctx; + struct clk_hw **hws; reg_base = of_iomap(np, 0); if (!reg_base) { @@ -3701,8 +3702,10 @@ static void __init exynos5433_cmu_apollo_init(struct device_node *np) samsung_clk_register_gate(ctx, apollo_gate_clks, ARRAY_SIZE(apollo_gate_clks)); + hws = ctx->clk_data.hws; + exynos_register_cpu_clock(ctx, CLK_SCLK_APOLLO, "apolloclk", - mout_apollo_p[0], mout_apollo_p[1], 0x200, + hws[CLK_MOUT_APOLLO_PLL], hws[CLK_MOUT_BUS_PLL_APOLLO_USER], 0x200, exynos5433_apolloclk_d, ARRAY_SIZE(exynos5433_apolloclk_d), CLK_CPU_HAS_E5433_REGS_LAYOUT); @@ -3933,6 +3936,7 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) { void __iomem *reg_base; struct samsung_clk_provider *ctx; + struct clk_hw **hws; reg_base = of_iomap(np, 0); if (!reg_base) { @@ -3955,8 +3959,10 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) samsung_clk_register_gate(ctx, atlas_gate_clks, ARRAY_SIZE(atlas_gate_clks)); + hws = ctx->clk_data.hws; + exynos_register_cpu_clock(ctx, CLK_SCLK_ATLAS, "atlasclk", - mout_atlas_p[0], mout_atlas_p[1], 0x200, + hws[CLK_MOUT_ATLAS_PLL], hws[CLK_MOUT_BUS_PLL_ATLAS_USER], 0x200, exynos5433_atlasclk_d, ARRAY_SIZE(exynos5433_atlasclk_d), CLK_CPU_HAS_E5433_REGS_LAYOUT); diff --git a/drivers/clk/socfpga/clk-agilex.c b/drivers/clk/socfpga/clk-agilex.c index 8fb12cbe0208..bb3e80928ebe 100644 --- a/drivers/clk/socfpga/clk-agilex.c +++ b/drivers/clk/socfpga/clk-agilex.c @@ -21,19 +21,6 @@ static const struct clk_parent_data pll_mux[] = { .name = "f2s-free-clk", }, }; -static const struct clk_parent_data cntr_mux[] = { - { .fw_name = "main_pll", - .name = "main_pll", }, - { .fw_name = "periph_pll", - .name = "periph_pll", }, - { .fw_name = "osc1", - .name = "osc1", }, - { .fw_name = "cb-intosc-hs-div2-clk", - .name = "cb-intosc-hs-div2-clk", }, - { .fw_name = "f2s-free-clk", - .name = "f2s-free-clk", }, -}; - static const struct clk_parent_data boot_mux[] = { { .fw_name = "osc1", .name = "osc1", }, diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index cdf333003c30..ce5f5847d5d3 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -17,6 +17,16 @@ config SUN50I_A64_CCU default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST +config SUN50I_A100_CCU + bool "Support for the Allwinner A100 CCU" + default ARM64 && ARCH_SUNXI + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + +config SUN50I_A100_R_CCU + bool "Support for the Allwinner A100 PRCM CCU" + default ARM64 && ARCH_SUNXI + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + config SUN50I_H6_CCU bool "Support for the Allwinner H6 CCU" default ARM64 && ARCH_SUNXI diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 4c7bee883f2f..3eb5cff40eac 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -23,6 +23,8 @@ obj-y += ccu_mp.o # SoC support obj-$(CONFIG_SUNIV_F1C100S_CCU) += ccu-suniv-f1c100s.o obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o +obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o +obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c new file mode 100644 index 000000000000..a56142b90993 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Yangtao Li <frank@allwinnertech.com> + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_nm.h" + +#include "ccu-sun50i-a100-r.h" + +static const char * const cpus_r_apb2_parents[] = { "dcxo24M", "osc32k", + "iosc", "pll-periph0" }; +static const struct ccu_mux_var_prediv cpus_r_apb2_predivs[] = { + { .index = 3, .shift = 0, .width = 5 }, +}; + +static struct ccu_div r_cpus_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 24, + .width = 2, + + .var_predivs = cpus_r_apb2_predivs, + .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs), + }, + + .common = { + .reg = 0x000, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("cpus", + cpus_r_apb2_parents, + &ccu_div_ops, + 0), + }, +}; + +static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &r_cpus_clk.common.hw, 1, 1, 0); + +static struct ccu_div r_apb1_clk = { + .div = _SUNXI_CCU_DIV(0, 2), + + .common = { + .reg = 0x00c, + .hw.init = CLK_HW_INIT("r-apb1", + "r-ahb", + &ccu_div_ops, + 0), + }, +}; + +static struct ccu_div r_apb2_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 24, + .width = 2, + + .var_predivs = cpus_r_apb2_predivs, + .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs), + }, + + .common = { + .reg = 0x010, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("r-apb2", + cpus_r_apb2_parents, + &ccu_div_ops, + 0), + }, +}; + +static const struct clk_parent_data clk_parent_r_apb1[] = { + { .hw = &r_apb1_clk.common.hw }, +}; + +static const struct clk_parent_data clk_parent_r_apb2[] = { + { .hw = &r_apb2_clk.common.hw }, +}; + +static SUNXI_CCU_GATE_DATA(r_apb1_timer_clk, "r-apb1-timer", clk_parent_r_apb1, + 0x11c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(r_apb1_twd_clk, "r-apb1-twd", clk_parent_r_apb1, + 0x12c, BIT(0), 0); + +static const char * const r_apb1_pwm_clk_parents[] = { "dcxo24M", "osc32k", + "iosc" }; +static SUNXI_CCU_MUX(r_apb1_pwm_clk, "r-apb1-pwm", r_apb1_pwm_clk_parents, + 0x130, 24, 2, 0); + +static SUNXI_CCU_GATE_DATA(r_apb1_bus_pwm_clk, "r-apb1-bus-pwm", + clk_parent_r_apb1, 0x13c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(r_apb1_ppu_clk, "r-apb1-ppu", clk_parent_r_apb1, + 0x17c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(r_apb2_uart_clk, "r-apb2-uart", clk_parent_r_apb2, + 0x18c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(r_apb2_i2c0_clk, "r-apb2-i2c0", clk_parent_r_apb2, + 0x19c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(r_apb2_i2c1_clk, "r-apb2-i2c1", clk_parent_r_apb2, + 0x19c, BIT(1), 0); + +static const char * const r_apb1_ir_rx_parents[] = { "osc32k", "dcxo24M" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(r_apb1_ir_rx_clk, "r-apb1-ir-rx", + r_apb1_ir_rx_parents, 0x1c0, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_DATA(r_apb1_bus_ir_rx_clk, "r-apb1-bus-ir-rx", + clk_parent_r_apb1, 0x1cc, BIT(0), 0); + +static SUNXI_CCU_GATE(r_ahb_bus_rtc_clk, "r-ahb-rtc", "r-ahb", + 0x20c, BIT(0), 0); + +static struct ccu_common *sun50i_a100_r_ccu_clks[] = { + &r_cpus_clk.common, + &r_apb1_clk.common, + &r_apb2_clk.common, + &r_apb1_timer_clk.common, + &r_apb1_twd_clk.common, + &r_apb1_pwm_clk.common, + &r_apb1_bus_pwm_clk.common, + &r_apb1_ppu_clk.common, + &r_apb2_uart_clk.common, + &r_apb2_i2c0_clk.common, + &r_apb2_i2c1_clk.common, + &r_apb1_ir_rx_clk.common, + &r_apb1_bus_ir_rx_clk.common, + &r_ahb_bus_rtc_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_a100_r_hw_clks = { + .hws = { + [CLK_R_CPUS] = &r_cpus_clk.common.hw, + [CLK_R_AHB] = &r_ahb_clk.hw, + [CLK_R_APB1] = &r_apb1_clk.common.hw, + [CLK_R_APB2] = &r_apb2_clk.common.hw, + [CLK_R_APB1_TIMER] = &r_apb1_timer_clk.common.hw, + [CLK_R_APB1_TWD] = &r_apb1_twd_clk.common.hw, + [CLK_R_APB1_PWM] = &r_apb1_pwm_clk.common.hw, + [CLK_R_APB1_BUS_PWM] = &r_apb1_bus_pwm_clk.common.hw, + [CLK_R_APB1_PPU] = &r_apb1_ppu_clk.common.hw, + [CLK_R_APB2_UART] = &r_apb2_uart_clk.common.hw, + [CLK_R_APB2_I2C0] = &r_apb2_i2c0_clk.common.hw, + [CLK_R_APB2_I2C1] = &r_apb2_i2c1_clk.common.hw, + [CLK_R_APB1_IR] = &r_apb1_ir_rx_clk.common.hw, + [CLK_R_APB1_BUS_IR] = &r_apb1_bus_ir_rx_clk.common.hw, + [CLK_R_AHB_BUS_RTC] = &r_ahb_bus_rtc_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_a100_r_ccu_resets[] = { + [RST_R_APB1_TIMER] = { 0x11c, BIT(16) }, + [RST_R_APB1_BUS_PWM] = { 0x13c, BIT(16) }, + [RST_R_APB1_PPU] = { 0x17c, BIT(16) }, + [RST_R_APB2_UART] = { 0x18c, BIT(16) }, + [RST_R_APB2_I2C0] = { 0x19c, BIT(16) }, + [RST_R_APB2_I2C1] = { 0x19c, BIT(17) }, + [RST_R_APB1_BUS_IR] = { 0x1cc, BIT(16) }, + [RST_R_AHB_BUS_RTC] = { 0x20c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun50i_a100_r_ccu_desc = { + .ccu_clks = sun50i_a100_r_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a100_r_ccu_clks), + + .hw_clks = &sun50i_a100_r_hw_clks, + + .resets = sun50i_a100_r_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_a100_r_ccu_resets), +}; + +static int sun50i_a100_r_ccu_probe(struct platform_device *pdev) +{ + void __iomem *reg; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_r_ccu_desc); +} + +static const struct of_device_id sun50i_a100_r_ccu_ids[] = { + { .compatible = "allwinner,sun50i-a100-r-ccu" }, + { } +}; + +static struct platform_driver sun50i_a100_r_ccu_driver = { + .probe = sun50i_a100_r_ccu_probe, + .driver = { + .name = "sun50i-a100-r-ccu", + .of_match_table = sun50i_a100_r_ccu_ids, + }, +}; +module_platform_driver(sun50i_a100_r_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h new file mode 100644 index 000000000000..3a8f187a51b7 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Yangtao Li <frank@allwinnertech.com> + */ + +#ifndef _CCU_SUN50I_A100_R_H +#define _CCU_SUN50I_A100_R_H + +#include <dt-bindings/clock/sun50i-a100-r-ccu.h> +#include <dt-bindings/reset/sun50i-a100-r-ccu.h> + +#define CLK_R_CPUS 0 +#define CLK_R_AHB 1 + +/* exported except APB1 for R_PIO */ + +#define CLK_R_APB2 3 + +#define CLK_NUMBER (CLK_R_AHB_BUS_RTC + 1) + +#endif /* _CCU_SUN50I_A100_R_H */ diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c new file mode 100644 index 000000000000..81b48c73d389 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c @@ -0,0 +1,1276 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Yangtao Li <frank@allwinnertech.com> + */ + +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" + +#include "ccu-sun50i-a100.h" + +#define SUN50I_A100_PLL_SDM_ENABLE BIT(24) +#define SUN50I_A100_PLL_OUTPUT_ENABLE BIT(27) +#define SUN50I_A100_PLL_LOCK BIT(28) +#define SUN50I_A100_PLL_LOCK_ENABLE BIT(29) +#define SUN50I_A100_PLL_ENABLE BIT(31) + +#define SUN50I_A100_PLL_PERIPH1_PATTERN0 0xd1303333 + +/* + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However + * P should only be used for output frequencies lower than 288 MHz. + * + * For now we can just model it as a multiplier clock, and force P to /1. + * + * The M factor is present in the register's description, but not in the + * frequency formula, and it's documented as "M is only used for backdoor + * testing", so it's not modelled and then force to 0. + */ +#define SUN50I_A100_PLL_CPUX_REG 0x000 +static struct ccu_mult pll_cpux_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", "dcxo24M", + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ +#define SUN50I_A100_PLL_DDR0_REG 0x010 +static struct ccu_nkmp pll_ddr0_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x010, + .hw.init = CLK_HW_INIT("pll-ddr0", "dcxo24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE | + CLK_IS_CRITICAL), + }, +}; + +#define SUN50I_A100_PLL_PERIPH0_REG 0x020 +static struct ccu_nkmp pll_periph0_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 2, + .common = { + .reg = 0x020, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph0", "dcxo24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_A100_PLL_PERIPH1_REG 0x028 +static struct ccu_nkmp pll_periph1_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .fixed_post_div = 2, + .common = { + .reg = 0x028, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph1", "dcxo24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; +#define SUN50I_A100_PLL_PERIPH1_PATTERN0_REG 0x128 + +#define SUN50I_A100_PLL_GPU_REG 0x030 +static struct ccu_nkmp pll_gpu_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x030, + .hw.init = CLK_HW_INIT("pll-gpu", "dcxo24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * For Video PLLs, the output divider is described as "used for testing" + * in the user manual. So it's not modelled and forced to 0. + */ +#define SUN50I_A100_PLL_VIDEO0_REG 0x040 +static struct ccu_nm pll_video0_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x040, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video0", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_A100_PLL_VIDEO1_REG 0x048 +static struct ccu_nm pll_video1_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x048, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video1", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_A100_PLL_VIDEO2_REG 0x050 +static struct ccu_nm pll_video2_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x050, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video2", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_A100_PLL_VE_REG 0x058 +static struct ccu_nkmp pll_ve_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x058, + .hw.init = CLK_HW_INIT("pll-ve", "dcxo24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * The COM PLL has m0 dividers in addition to the usual N, M + * factors. Since we only need 1 frequencies from this PLL: 45.1584 MHz, + * ignore it for now. + */ +#define SUN50I_A100_PLL_COM_REG 0x060 +static struct ccu_sdm_setting pll_com_sdm_table[] = { + { .rate = 451584000, .pattern = 0xc0014396, .m = 2, .n = 37 }, +}; + +static struct ccu_nm pll_com_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(0, 1), + .sdm = _SUNXI_CCU_SDM(pll_com_sdm_table, BIT(24), + 0x160, BIT(31)), + .common = { + .reg = 0x060, + .features = CCU_FEATURE_SIGMA_DELTA_MOD, + .hw.init = CLK_HW_INIT("pll-com", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN50I_A100_PLL_VIDEO3_REG 0x068 +static struct ccu_nm pll_video3_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .fixed_post_div = 4, + .common = { + .reg = 0x068, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-video3", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * The Audio PLL has m0, m1 dividers in addition to the usual N, M + * factors. Since we only need 4 frequencies from this PLL: 22.5792 MHz, + * 24.576 MHz, 90.3168MHz and 98.304MHz ignore them for now. + * Enforce the default for them, which is m0 = 1, m1 = 0. + */ +#define SUN50I_A100_PLL_AUDIO_REG 0x078 +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 45158400, .pattern = 0xc001bcd3, .m = 18, .n = 33 }, + { .rate = 49152000, .pattern = 0xc001eb85, .m = 20, .n = 40 }, + { .rate = 180633600, .pattern = 0xc001288d, .m = 3, .n = 22 }, + { .rate = 196608000, .pattern = 0xc001eb85, .m = 5, .n = 40 }, +}; + +static struct ccu_nm pll_audio_clk = { + .enable = SUN50I_A100_PLL_OUTPUT_ENABLE, + .lock = SUN50I_A100_PLL_LOCK, + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(16, 6), + .fixed_post_div = 2, + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24), + 0x178, BIT(31)), + .common = { + .reg = 0x078, + .features = CCU_FEATURE_FIXED_POSTDIV | + CCU_FEATURE_SIGMA_DELTA_MOD, + .hw.init = CLK_HW_INIT("pll-audio", "dcxo24M", + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const char * const cpux_parents[] = { "dcxo24M", "osc32k", + "iosc", "pll-cpux", + "pll-periph0" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0); +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0); + +static const char * const psi_ahb1_ahb2_parents[] = { "dcxo24M", "osc32k", + "iosc", "pll-periph0", + "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2", + psi_ahb1_ahb2_parents, 0x510, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); + +static const char * const ahb3_apb1_apb2_parents[] = { "dcxo24M", "osc32k", + "psi-ahb1-ahb2", + "pll-periph0", + "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); + +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); + +static const char * const mbus_parents[] = { "dcxo24M", "pll-ddr0", + "pll-periph0", + "pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540, + 0, 3, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_IS_CRITICAL); + +static const char * const de_parents[] = { "pll-com", "pll-periph0-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de0", de_parents, 0x600, + 0, 4, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2", + 0x60c, BIT(0), 0); + +static const char * const g2d_parents[] = { "pll-com", "pll-periph0-2x", + "pll-video0-2x", "pll-video1-2x", + "pll-video2-2x"}; +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d", + g2d_parents, + 0x630, + 0, 4, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2", + 0x63c, BIT(0), 0); + +static const char * const gpu_parents[] = { "pll-gpu" }; +static SUNXI_CCU_M_WITH_MUX_GATE(gpu_clk, "gpu", gpu_parents, 0x670, + 0, 2, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2", + 0x67c, BIT(0), 0); + +static const char * const ce_parents[] = { "dcxo24M", "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2", + 0x68c, BIT(0), 0); + +static const char * const ve_parents[] = { "pll-ve" }; +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, + 0, 3, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2", + 0x69c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2", + 0x70c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "psi-ahb1-ahb2", + 0x71c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "psi-ahb1-ahb2", + 0x72c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2", + 0x73c, BIT(0), 0); + +static SUNXI_CCU_GATE(avs_clk, "avs", "dcxo24M", 0x740, BIT(31), 0); + +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2", + 0x78c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2", + 0x79c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0); + +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus", + 0x804, BIT(0), 0); +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus", + 0x804, BIT(1), 0); +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus", + 0x804, BIT(2), 0); +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus", + 0x804, BIT(5), 0); +static SUNXI_CCU_GATE(mbus_csi_clk, "mbus-csi", "mbus", + 0x804, BIT(8), 0); +static SUNXI_CCU_GATE(mbus_isp_clk, "mbus-isp", "mbus", + 0x804, BIT(9), 0); +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus", + 0x804, BIT(10), 0); + +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2", + 0x80c, BIT(0), CLK_IS_CRITICAL); + +static const char * const nand_spi_parents[] = { "dcxo24M", + "pll-periph0", + "pll-periph1", + "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0); + +static const char * const mmc_parents[] = { "dcxo24M", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0", mmc_parents, 0x830, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + CLK_SET_RATE_NO_REPARENT); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1", mmc_parents, 0x834, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + CLK_SET_RATE_NO_REPARENT); + +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc2_clk, "mmc2", mmc_parents, 0x838, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 2, /* post-div */ + CLK_SET_RATE_NO_REPARENT); + +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0); + +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi2_clk, "spi2", nand_spi_parents, 0x948, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_spi2_clk, "bus-spi2", "ahb3", 0x96c, BIT(2), 0); + +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970, + BIT(31) | BIT(30), 0); + +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb3", 0x97c, BIT(0), 0); + +static const char * const ir_parents[] = { "osc32k", "iosc", + "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_rx_clk, "ir-rx", ir_parents, 0x990, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ir_rx_clk, "bus-ir-rx", "ahb3", 0x99c, BIT(0), 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_parents, 0x9c0, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ir_tx_clk, "bus-ir-tx", "apb1", 0x9cc, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_gpadc_clk, "bus-gpadc", "apb1", 0x9ec, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0); + +static const char * const audio_parents[] = { "pll-audio", "pll-com-audio" }; +static struct ccu_div i2s0_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa10, + .hw.init = CLK_HW_INIT_PARENTS("i2s0", + audio_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static struct ccu_div i2s1_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa14, + .hw.init = CLK_HW_INIT_PARENTS("i2s1", + audio_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static struct ccu_div i2s2_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa18, + .hw.init = CLK_HW_INIT_PARENTS("i2s2", + audio_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static struct ccu_div i2s3_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa1c, + .hw.init = CLK_HW_INIT_PARENTS("i2s3", + audio_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", 0xa20, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", 0xa20, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", 0xa20, BIT(2), 0); +static SUNXI_CCU_GATE(bus_i2s3_clk, "bus-i2s3", "apb1", 0xa20, BIT(3), 0); + +static struct ccu_div spdif_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa24, + .hw.init = CLK_HW_INIT_PARENTS("spdif", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0); + +static struct ccu_div dmic_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0xa40, + .hw.init = CLK_HW_INIT_PARENTS("dmic", + audio_parents, + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_dac_clk, "audio-codec-dac", + audio_parents, 0xa50, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_adc_clk, "audio-codec-adc", + audio_parents, 0xa54, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x", + audio_parents, 0xa58, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c, + BIT(0), 0); + +/* + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports. + * We will force them to 0 (12M divided from 48M). + */ +#define SUN50I_A100_USB0_CLK_REG 0xa70 +#define SUN50I_A100_USB1_CLK_REG 0xa74 + +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "dcxo24M", 0xa70, BIT(29), 0); + +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "dcxo24M", 0xa74, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0); + +static SUNXI_CCU_GATE(bus_lradc_clk, "bus-lradc", "ahb3", 0xa9c, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_dpss_top0_clk, "bus-dpss-top0", "ahb3", + 0xabc, BIT(0), 0); + +static SUNXI_CCU_GATE(bus_dpss_top1_clk, "bus-dpss-top1", "ahb3", + 0xacc, BIT(0), 0); + +static const char * const mipi_dsi_parents[] = { "dcxo24M", "pll-periph0-2x", + "pll-periph0" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", + mipi_dsi_parents, + 0xb24, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb3", + 0xb4c, BIT(0), 0); + +static const char * const tcon_lcd_parents[] = { "pll-video0-4x", + "pll-video1-4x", + "pll-video2-4x", + "pll-video3-4x", + "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_lcd_clk, "tcon-lcd0", + tcon_lcd_parents, 0xb60, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_tcon_lcd_clk, "bus-tcon-lcd0", "ahb3", + 0xb7c, BIT(0), 0); + +static const char * const ledc_parents[] = { "dcxo24M", + "pll-periph0" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ledc_clk, "ledc", + ledc_parents, 0xbf0, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_ledc_clk, "bus-ledc", "ahb3", 0xbfc, BIT(0), 0); + +static const char * const csi_top_parents[] = { "pll-periph0-2x", + "pll-video0-2x", + "pll-video1-2x", + "pll-video2-2x", + "pll-video3-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_top_clk, "csi-top", + csi_top_parents, 0xc04, + 0, 4, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const csi0_mclk_parents[] = { "dcxo24M", "pll-video2", + "pll-video3", "pll-video0", + "pll-video1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi0_mclk_clk, "csi0-mclk", + csi0_mclk_parents, 0xc08, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const csi1_mclk_parents[] = { "dcxo24M", "pll-video3", + "pll-video0", "pll-video1", + "pll-video2" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi1_mclk_clk, "csi1-mclk", + csi1_mclk_parents, 0xc0c, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb3", 0xc1c, BIT(0), 0); + +static const char * const csi_isp_parents[] = { "pll-periph0-2x", + "pll-video0-2x", + "pll-video1-2x", + "pll-video2-2x", + "pll-video3-2x" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_isp_clk, "csi-isp", + csi_isp_parents, 0xc20, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +/* Fixed factor clocks */ +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0); + +static CLK_FIXED_FACTOR_HW(pll_com_audio_clk, "pll-com-audio", + &pll_com_clk.common.hw, + 5, 1, CLK_SET_RATE_PARENT); + +static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x", + &pll_periph0_clk.common.hw, + 1, 2, 0); + +static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x", + &pll_periph1_clk.common.hw, + 1, 2, 0); + +static const struct clk_hw *pll_video0_parents[] = { + &pll_video0_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video0_4x_clk, "pll-video0-4x", + pll_video0_parents, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video0_2x_clk, "pll-video0-2x", + pll_video0_parents, + 1, 2, CLK_SET_RATE_PARENT); + +static const struct clk_hw *pll_video1_parents[] = { + &pll_video1_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video1_4x_clk, "pll-video1-4x", + pll_video1_parents, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video1_2x_clk, "pll-video1-2x", + pll_video1_parents, + 1, 2, CLK_SET_RATE_PARENT); + +static const struct clk_hw *pll_video2_parents[] = { + &pll_video2_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video2_4x_clk, "pll-video2-4x", + pll_video2_parents, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video2_2x_clk, "pll-video2-2x", + pll_video2_parents, + 1, 2, CLK_SET_RATE_PARENT); + +static const struct clk_hw *pll_video3_parents[] = { + &pll_video3_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video3_4x_clk, "pll-video3-4x", + pll_video3_parents, + 1, 4, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video3_2x_clk, "pll-video3-2x", + pll_video3_parents, + 1, 2, CLK_SET_RATE_PARENT); + +static struct ccu_common *sun50i_a100_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_ddr0_clk.common, + &pll_periph0_clk.common, + &pll_periph1_clk.common, + &pll_gpu_clk.common, + &pll_video0_clk.common, + &pll_video1_clk.common, + &pll_video2_clk.common, + &pll_video3_clk.common, + &pll_ve_clk.common, + &pll_com_clk.common, + &pll_audio_clk.common, + &cpux_clk.common, + &axi_clk.common, + &cpux_apb_clk.common, + &psi_ahb1_ahb2_clk.common, + &ahb3_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &mbus_clk.common, + &de_clk.common, + &bus_de_clk.common, + &g2d_clk.common, + &bus_g2d_clk.common, + &gpu_clk.common, + &bus_gpu_clk.common, + &ce_clk.common, + &bus_ce_clk.common, + &ve_clk.common, + &bus_ve_clk.common, + &bus_dma_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_hstimer_clk.common, + &avs_clk.common, + &bus_dbg_clk.common, + &bus_psi_clk.common, + &bus_pwm_clk.common, + &bus_iommu_clk.common, + &mbus_dma_clk.common, + &mbus_ve_clk.common, + &mbus_ce_clk.common, + &mbus_nand_clk.common, + &mbus_csi_clk.common, + &mbus_isp_clk.common, + &mbus_g2d_clk.common, + &bus_dram_clk.common, + &nand0_clk.common, + &nand1_clk.common, + &bus_nand_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_i2c3_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &spi2_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_spi2_clk.common, + &emac_25m_clk.common, + &bus_emac_clk.common, + &ir_rx_clk.common, + &bus_ir_rx_clk.common, + &ir_tx_clk.common, + &bus_ir_tx_clk.common, + &bus_gpadc_clk.common, + &bus_ths_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &i2s3_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2s3_clk.common, + &spdif_clk.common, + &bus_spdif_clk.common, + &dmic_clk.common, + &bus_dmic_clk.common, + &audio_codec_dac_clk.common, + &audio_codec_adc_clk.common, + &audio_codec_4x_clk.common, + &bus_audio_codec_clk.common, + &usb_ohci0_clk.common, + &usb_phy0_clk.common, + &usb_ohci1_clk.common, + &usb_phy1_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_otg_clk.common, + &bus_lradc_clk.common, + &bus_dpss_top0_clk.common, + &bus_dpss_top1_clk.common, + &mipi_dsi_clk.common, + &bus_mipi_dsi_clk.common, + &tcon_lcd_clk.common, + &bus_tcon_lcd_clk.common, + &ledc_clk.common, + &bus_ledc_clk.common, + &csi_top_clk.common, + &csi0_mclk_clk.common, + &csi1_mclk_clk.common, + &bus_csi_clk.common, + &csi_isp_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_a100_hw_clks = { + .hws = { + [CLK_OSC12M] = &osc12M_clk.hw, + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw, + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_VIDEO1_2X] = &pll_video1_2x_clk.hw, + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw, + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw, + [CLK_PLL_VIDEO2_2X] = &pll_video2_2x_clk.hw, + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw, + [CLK_PLL_VIDEO3] = &pll_video3_clk.common.hw, + [CLK_PLL_VIDEO3_2X] = &pll_video3_2x_clk.hw, + [CLK_PLL_VIDEO3_4X] = &pll_video3_4x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_COM] = &pll_com_clk.common.hw, + [CLK_PLL_COM_AUDIO] = &pll_com_audio_clk.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw, + [CLK_AHB3] = &ahb3_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_G2D] = &g2d_clk.common.hw, + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_BUS_PSI] = &bus_psi_clk.common.hw, + [CLK_BUS_PWM] = &bus_pwm_clk.common.hw, + [CLK_BUS_IOMMU] = &bus_iommu_clk.common.hw, + [CLK_MBUS_DMA] = &mbus_dma_clk.common.hw, + [CLK_MBUS_VE] = &mbus_ve_clk.common.hw, + [CLK_MBUS_CE] = &mbus_ce_clk.common.hw, + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw, + [CLK_MBUS_CSI] = &mbus_csi_clk.common.hw, + [CLK_MBUS_ISP] = &mbus_isp_clk.common.hw, + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_NAND0] = &nand0_clk.common.hw, + [CLK_NAND1] = &nand1_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_I2C3] = &bus_i2c3_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_SPI2] = &spi2_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_SPI2] = &bus_spi2_clk.common.hw, + [CLK_EMAC_25M] = &emac_25m_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_IR_RX] = &ir_rx_clk.common.hw, + [CLK_BUS_IR_RX] = &bus_ir_rx_clk.common.hw, + [CLK_IR_TX] = &ir_tx_clk.common.hw, + [CLK_BUS_IR_TX] = &bus_ir_tx_clk.common.hw, + [CLK_BUS_GPADC] = &bus_gpadc_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_I2S3] = &i2s3_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_I2S3] = &bus_i2s3_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_DMIC] = &dmic_clk.common.hw, + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, + [CLK_AUDIO_DAC] = &audio_codec_dac_clk.common.hw, + [CLK_AUDIO_ADC] = &audio_codec_adc_clk.common.hw, + [CLK_AUDIO_4X] = &audio_codec_4x_clk.common.hw, + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_LRADC] = &bus_lradc_clk.common.hw, + [CLK_BUS_DPSS_TOP0] = &bus_dpss_top0_clk.common.hw, + [CLK_BUS_DPSS_TOP1] = &bus_dpss_top1_clk.common.hw, + [CLK_MIPI_DSI] = &mipi_dsi_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_TCON_LCD] = &tcon_lcd_clk.common.hw, + [CLK_BUS_TCON_LCD] = &bus_tcon_lcd_clk.common.hw, + [CLK_LEDC] = &ledc_clk.common.hw, + [CLK_BUS_LEDC] = &bus_ledc_clk.common.hw, + [CLK_CSI_TOP] = &csi_top_clk.common.hw, + [CLK_CSI0_MCLK] = &csi0_mclk_clk.common.hw, + [CLK_CSI1_MCLK] = &csi1_mclk_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_CSI_ISP] = &csi_isp_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_a100_ccu_resets[] = { + [RST_MBUS] = { 0x540, BIT(30) }, + + [RST_BUS_DE] = { 0x60c, BIT(16) }, + [RST_BUS_G2D] = { 0x63c, BIT(16) }, + [RST_BUS_GPU] = { 0x67c, BIT(16) }, + [RST_BUS_CE] = { 0x68c, BIT(16) }, + [RST_BUS_VE] = { 0x69c, BIT(16) }, + [RST_BUS_DMA] = { 0x70c, BIT(16) }, + [RST_BUS_MSGBOX] = { 0x71c, BIT(16) }, + [RST_BUS_SPINLOCK] = { 0x72c, BIT(16) }, + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, + [RST_BUS_DBG] = { 0x78c, BIT(16) }, + [RST_BUS_PSI] = { 0x79c, BIT(16) }, + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, + [RST_BUS_NAND] = { 0x82c, BIT(16) }, + [RST_BUS_MMC0] = { 0x84c, BIT(16) }, + [RST_BUS_MMC1] = { 0x84c, BIT(17) }, + [RST_BUS_MMC2] = { 0x84c, BIT(18) }, + [RST_BUS_UART0] = { 0x90c, BIT(16) }, + [RST_BUS_UART1] = { 0x90c, BIT(17) }, + [RST_BUS_UART2] = { 0x90c, BIT(18) }, + [RST_BUS_UART3] = { 0x90c, BIT(19) }, + [RST_BUS_UART4] = { 0x90c, BIT(20) }, + [RST_BUS_I2C0] = { 0x91c, BIT(16) }, + [RST_BUS_I2C1] = { 0x91c, BIT(17) }, + [RST_BUS_I2C2] = { 0x91c, BIT(18) }, + [RST_BUS_I2C3] = { 0x91c, BIT(19) }, + [RST_BUS_SPI0] = { 0x96c, BIT(16) }, + [RST_BUS_SPI1] = { 0x96c, BIT(17) }, + [RST_BUS_SPI2] = { 0x96c, BIT(18) }, + [RST_BUS_EMAC] = { 0x97c, BIT(16) }, + [RST_BUS_IR_RX] = { 0x99c, BIT(16) }, + [RST_BUS_IR_TX] = { 0x9cc, BIT(16) }, + [RST_BUS_GPADC] = { 0x9ec, BIT(16) }, + [RST_BUS_THS] = { 0x9fc, BIT(16) }, + [RST_BUS_I2S0] = { 0xa20, BIT(16) }, + [RST_BUS_I2S1] = { 0xa20, BIT(17) }, + [RST_BUS_I2S2] = { 0xa20, BIT(18) }, + [RST_BUS_I2S3] = { 0xa20, BIT(19) }, + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) }, + + [RST_USB_PHY0] = { 0xa70, BIT(30) }, + [RST_USB_PHY1] = { 0xa74, BIT(30) }, + + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, + + [RST_BUS_LRADC] = { 0xa9c, BIT(16) }, + [RST_BUS_DPSS_TOP0] = { 0xabc, BIT(16) }, + [RST_BUS_DPSS_TOP1] = { 0xacc, BIT(16) }, + [RST_BUS_MIPI_DSI] = { 0xb4c, BIT(16) }, + [RST_BUS_TCON_LCD] = { 0xb7c, BIT(16) }, + [RST_BUS_LVDS] = { 0xbac, BIT(16) }, + [RST_BUS_LEDC] = { 0xbfc, BIT(16) }, + [RST_BUS_CSI] = { 0xc1c, BIT(16) }, + [RST_BUS_CSI_ISP] = { 0xc2c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun50i_a100_ccu_desc = { + .ccu_clks = sun50i_a100_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a100_ccu_clks), + + .hw_clks = &sun50i_a100_hw_clks, + + .resets = sun50i_a100_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_a100_ccu_resets), +}; + +static const u32 sun50i_a100_pll_regs[] = { + SUN50I_A100_PLL_CPUX_REG, + SUN50I_A100_PLL_DDR0_REG, + SUN50I_A100_PLL_PERIPH0_REG, + SUN50I_A100_PLL_PERIPH1_REG, + SUN50I_A100_PLL_GPU_REG, + SUN50I_A100_PLL_VIDEO0_REG, + SUN50I_A100_PLL_VIDEO1_REG, + SUN50I_A100_PLL_VIDEO2_REG, + SUN50I_A100_PLL_VIDEO3_REG, + SUN50I_A100_PLL_VE_REG, + SUN50I_A100_PLL_COM_REG, + SUN50I_A100_PLL_AUDIO_REG, +}; + +static const u32 sun50i_a100_pll_video_regs[] = { + SUN50I_A100_PLL_VIDEO0_REG, + SUN50I_A100_PLL_VIDEO1_REG, + SUN50I_A100_PLL_VIDEO2_REG, + SUN50I_A100_PLL_VIDEO3_REG, +}; + +static const u32 sun50i_a100_usb2_clk_regs[] = { + SUN50I_A100_USB0_CLK_REG, + SUN50I_A100_USB1_CLK_REG, +}; + +static struct ccu_pll_nb sun50i_a100_pll_cpu_nb = { + .common = &pll_cpux_clk.common, + /* copy from pll_cpux_clk */ + .enable = BIT(27), + .lock = BIT(28), +}; + +static struct ccu_mux_nb sun50i_a100_cpu_nb = { + .common = &cpux_clk.common, + .cm = &cpux_clk.mux, + .delay_us = 1, + .bypass_index = 4, /* index of pll periph0 */ +}; + +static int sun50i_a100_ccu_probe(struct platform_device *pdev) +{ + void __iomem *reg; + u32 val; + int i, ret; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* + * Enable lock and enable bits on all PLLs. + * + * Due to the current design, multiple PLLs share one power switch, + * so switching PLL is easy to cause stability problems. + * When initializing, we enable them by default. When disable, + * we only turn off the output of PLL. + */ + for (i = 0; i < ARRAY_SIZE(sun50i_a100_pll_regs); i++) { + val = readl(reg + sun50i_a100_pll_regs[i]); + val |= SUN50I_A100_PLL_LOCK_ENABLE | SUN50I_A100_PLL_ENABLE; + writel(val, reg + sun50i_a100_pll_regs[i]); + } + + /* + * In order to pass the EMI certification, the SDM function of + * the peripheral 1 bus is enabled, and the frequency is still + * calculated using the previous division factor. + */ + writel(SUN50I_A100_PLL_PERIPH1_PATTERN0, + reg + SUN50I_A100_PLL_PERIPH1_PATTERN0_REG); + + val = readl(reg + SUN50I_A100_PLL_PERIPH1_REG); + val |= SUN50I_A100_PLL_SDM_ENABLE; + writel(val, reg + SUN50I_A100_PLL_PERIPH1_REG); + + /* + * Force the output divider of video PLLs to 0. + * + * See the comment before pll-video0 definition for the reason. + */ + for (i = 0; i < ARRAY_SIZE(sun50i_a100_pll_video_regs); i++) { + val = readl(reg + sun50i_a100_pll_video_regs[i]); + val &= ~BIT(0); + writel(val, reg + sun50i_a100_pll_video_regs[i]); + } + + /* + * Enforce m1 = 0, m0 = 1 for Audio PLL + * + * See the comment before pll-audio definition for the reason. + */ + val = readl(reg + SUN50I_A100_PLL_AUDIO_REG); + val &= ~BIT(1); + val |= BIT(0); + writel(val, reg + SUN50I_A100_PLL_AUDIO_REG); + + /* + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz) + * + * This clock mux is still mysterious, and the code just enforces + * it to have a valid clock parent. + */ + for (i = 0; i < ARRAY_SIZE(sun50i_a100_usb2_clk_regs); i++) { + val = readl(reg + sun50i_a100_usb2_clk_regs[i]); + val &= ~GENMASK(25, 24); + writel(val, reg + sun50i_a100_usb2_clk_regs[i]); + } + + ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_ccu_desc); + if (ret) + return ret; + + /* Gate then ungate PLL CPU after any rate changes */ + ccu_pll_notifier_register(&sun50i_a100_pll_cpu_nb); + + /* Reparent CPU during PLL CPU rate changes */ + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, + &sun50i_a100_cpu_nb); + + return 0; +} + +static const struct of_device_id sun50i_a100_ccu_ids[] = { + { .compatible = "allwinner,sun50i-a100-ccu" }, + { } +}; + +static struct platform_driver sun50i_a100_ccu_driver = { + .probe = sun50i_a100_ccu_probe, + .driver = { + .name = "sun50i-a100-ccu", + .of_match_table = sun50i_a100_ccu_ids, + }, +}; +module_platform_driver(sun50i_a100_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.h b/drivers/clk/sunxi-ng/ccu-sun50i-a100.h new file mode 100644 index 000000000000..21ce92bb1d5f --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Yangtao Li <frank@allwinnertech.com> + */ + +#ifndef _CCU_SUN50I_A100_H_ +#define _CCU_SUN50I_A100_H_ + +#include <dt-bindings/clock/sun50i-a100-ccu.h> +#include <dt-bindings/reset/sun50i-a100-ccu.h> + +#define CLK_OSC12M 0 +#define CLK_PLL_CPUX 1 +#define CLK_PLL_DDR0 2 + +/* PLL_PERIPH0 exported for PRCM */ + +#define CLK_PLL_PERIPH0_2X 4 +#define CLK_PLL_PERIPH1 5 +#define CLK_PLL_PERIPH1_2X 6 +#define CLK_PLL_GPU 7 +#define CLK_PLL_VIDEO0 8 +#define CLK_PLL_VIDEO0_2X 9 +#define CLK_PLL_VIDEO0_4X 10 +#define CLK_PLL_VIDEO1 11 +#define CLK_PLL_VIDEO1_2X 12 +#define CLK_PLL_VIDEO1_4X 13 +#define CLK_PLL_VIDEO2 14 +#define CLK_PLL_VIDEO2_2X 15 +#define CLK_PLL_VIDEO2_4X 16 +#define CLK_PLL_VIDEO3 17 +#define CLK_PLL_VIDEO3_2X 18 +#define CLK_PLL_VIDEO3_4X 19 +#define CLK_PLL_VE 20 +#define CLK_PLL_COM 21 +#define CLK_PLL_COM_AUDIO 22 +#define CLK_PLL_AUDIO 23 + +/* CPUX clock exported for DVFS */ + +#define CLK_AXI 25 +#define CLK_CPUX_APB 26 +#define CLK_PSI_AHB1_AHB2 27 +#define CLK_AHB3 28 + +/* APB1 clock exported for PIO */ + +#define CLK_APB2 30 + +/* All module clocks and bus gates are exported except DRAM */ + +#define CLK_BUS_DRAM 58 + +#define CLK_NUMBER (CLK_CSI_ISP + 1) + +#endif /* _CCU_SUN50I_A100_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 23bfe1d12f21..84153418453f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -45,18 +45,29 @@ static struct ccu_nkmp pll_cpu_clk = { * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN8I_R40_PLL_AUDIO_REG 0x008 -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", - "osc24M", 0x008, - 8, 7, /* N */ - 0, 5, /* M */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + pll_audio_sdm_table, BIT(24), + 0x284, BIT(31), + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0", "osc24M", 0x0010, @@ -952,10 +963,10 @@ static const struct clk_hw *clk_parent_pll_audio[] = { &pll_audio_base_clk.common.hw }; -/* We hardcode the divider to 4 for now */ +/* We hardcode the divider to 1 for now */ static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio", clk_parent_pll_audio, - 4, 1, CLK_SET_RATE_PARENT); + 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", clk_parent_pll_audio, 2, 1, CLK_SET_RATE_PARENT); @@ -1307,10 +1318,10 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_R40_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN8I_R40_PLL_AUDIO_REG); + writel(val | (0 << 16), reg + SUN8I_R40_PLL_AUDIO_REG); /* Force PLL-MIPI to MIPI mode */ val = readl(reg + SUN8I_R40_PLL_MIPI_REG); diff --git a/drivers/clk/tegra/clk-tegra210-emc.c b/drivers/clk/tegra/clk-tegra210-emc.c index 352a2c3fc374..971c919b2994 100644 --- a/drivers/clk/tegra/clk-tegra210-emc.c +++ b/drivers/clk/tegra/clk-tegra210-emc.c @@ -126,7 +126,7 @@ static int tegra210_clk_emc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned int i; int err; - if (!provider || !provider->configs || provider->num_configs == 0) + if (!provider->configs || provider->num_configs == 0) return -EINVAL; for (i = 0; i < provider->num_configs; i++) { diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index 1cae226759dd..f6f8a409f148 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -82,7 +82,12 @@ static int _omap2_clk_allow_idle(struct clk_hw_omap *clk) */ int omap2_clk_deny_idle(struct clk *clk) { - struct clk_hw *hw = __clk_get_hw(clk); + struct clk_hw *hw; + + if (!clk) + return -EINVAL; + + hw = __clk_get_hw(clk); if (omap2_clk_is_hw_omap(hw)) { struct clk_hw_omap *c = to_clk_hw_omap(hw); @@ -101,7 +106,12 @@ int omap2_clk_deny_idle(struct clk *clk) */ int omap2_clk_allow_idle(struct clk *clk) { - struct clk_hw *hw = __clk_get_hw(clk); + struct clk_hw *hw; + + if (!clk) + return -EINVAL; + + hw = __clk_get_hw(clk); if (omap2_clk_is_hw_omap(hw)) { struct clk_hw_omap *c = to_clk_hw_omap(hw); diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index b4cf578a69e1..4e27f88062e7 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -637,6 +637,7 @@ static const struct omap_clkctrl_reg_data dra7_l4sec_clkctrl_regs[] __initconst { DRA7_L4SEC_DES_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { DRA7_L4SEC_RNG_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_SOC_NONSEC, "l4_root_clk_div" }, { DRA7_L4SEC_SHAM_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, + { DRA7_L4SEC_SHAM2_CLKCTRL, NULL, CLKF_HW_SUP, "l3_iclk_div" }, { 0 }, }; diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index ee56306f79d5..700b7f44f671 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -148,10 +148,12 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) if (!omap2_clk_is_hw_omap(clk_hw)) { pr_warn("can't setup clkdm for basic clk %s\n", __clk_get_name(clk)); + clk_put(clk); continue; } to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name; omap2_init_clk_clkdm(clk_hw); + clk_put(clk); } } |