From 7b70689b07c1d336a5ad6906927aa413619029bd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Jul 2020 17:43:57 +0200 Subject: [PATCH 01/21] clk: meson: add sclk-ws driver This is yet another simple but odd driver for the audio block of the g12a and sm1 SoC families. For TDMOUT's sclk to be properly inverted, bit 29 of AUDIO_CLK_TDMOUT_x_CTRL should be the inverse of bit 28. IOW bit28 == !bit29 at all times This setting is automatically applied on axg and the manual setting was added on g12a. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20200729154359.1983085-2-jbrunet@baylibre.com --- drivers/clk/meson/clk-phase.c | 56 +++++++++++++++++++++++++++++++++++ drivers/clk/meson/clk-phase.h | 6 ++++ 2 files changed, 62 insertions(+) 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 "); 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 */ From cdabb1ffc7c2349b8930f752df1edcafc1d37cc1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Jul 2020 17:43:58 +0200 Subject: [PATCH 02/21] clk: meson: axg-audio: separate axg and g12a regmap tables There are more differences than what we initially thought. Let's keeps things clear and separate the axg and g12a regmap tables of the audio clock controller. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20200729154359.1983085-3-jbrunet@baylibre.com --- drivers/clk/meson/axg-audio.c | 135 ++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 53715e36326c..9918cb375de3 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -1209,13 +1209,132 @@ 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, + &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, + &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, + &tdmout_a_sclk, + &tdmout_b_sclk, + &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, @@ -1713,8 +1832,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, From 4fd433fd45514adc68aebf71a89a66590fdc792d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Jul 2020 17:43:59 +0200 Subject: [PATCH 03/21] clk: meson: axg-audio: fix g12a tdmout sclk inverter Fix the tdmout inverter of the g12a and following SoC families. This inverter is special and needs two bits to be the inverse of each other for the inverter to operate properly. Fixes: 075001385c66 ("clk: meson: axg-audio: add g12a support") Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20200729154359.1983085-4-jbrunet@baylibre.com --- drivers/clk/meson/axg-audio.c | 85 ++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 9918cb375de3..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, @@ -1322,9 +1357,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, + &axg_tdmout_a_sclk, + &axg_tdmout_b_sclk, + &axg_tdmout_c_sclk, &tdmin_a_lrclk, &tdmin_b_lrclk, &tdmin_c_lrclk, @@ -1447,9 +1482,9 @@ static struct clk_regmap *const g12a_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, @@ -1584,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, From 2f704c29699dc3809d80095da8cf2cd5d19b28c4 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 24 Jul 2020 14:56:08 +0800 Subject: [PATCH 04/21] dt-bindings: clk: sunxi-ccu: add compatible string for A100 CCU and R-CCU This patch adds binding to a100's ccu clock and r-ccu clock. Signed-off-by: Yangtao Li Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/5791b0a39e7ca2f1c11d3bade9ebeb7fece31230.1595572867.git.frank@allwinnertech.com --- .../devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml index 4d382128b711..3b45344ed758 100644 --- a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml +++ b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml @@ -36,6 +36,8 @@ properties: - allwinner,sun9i-a80-ccu - allwinner,sun50i-a64-ccu - allwinner,sun50i-a64-r-ccu + - allwinner,sun50i-a100-ccu + - allwinner,sun50i-a100-r-ccu - allwinner,sun50i-h5-ccu - allwinner,sun50i-h6-ccu - allwinner,sun50i-h6-r-ccu @@ -78,6 +80,7 @@ if: - allwinner,sun8i-a83t-r-ccu - allwinner,sun8i-h3-r-ccu - allwinner,sun50i-a64-r-ccu + - allwinner,sun50i-a100-r-ccu - allwinner,sun50i-h6-r-ccu then: @@ -94,7 +97,9 @@ else: if: properties: compatible: - const: allwinner,sun50i-h6-ccu + enum: + - allwinner,sun50i-a100-ccu + - allwinner,sun50i-h6-ccu then: properties: From fb038ce4db55cf2c911b6b221d10f06afe5f25af Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 24 Jul 2020 14:58:43 +0800 Subject: [PATCH 05/21] clk: sunxi-ng: add support for the Allwinner A100 CCU Add support for a100 in the sunxi-ng CCU framework. Signed-off-by: Yangtao Li Signed-off-by: Maxime Ripard Acked-by: Rob Herring Link: https://lore.kernel.org/r/1eb41bf6c966a0e54820200650d27a5d4f2ac160.1595572867.git.frank@allwinnertech.com --- drivers/clk/sunxi-ng/Kconfig | 10 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c | 214 +++ drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h | 21 + drivers/clk/sunxi-ng/ccu-sun50i-a100.c | 1276 +++++++++++++++++ drivers/clk/sunxi-ng/ccu-sun50i-a100.h | 56 + include/dt-bindings/clock/sun50i-a100-ccu.h | 116 ++ include/dt-bindings/clock/sun50i-a100-r-ccu.h | 23 + include/dt-bindings/reset/sun50i-a100-ccu.h | 68 + include/dt-bindings/reset/sun50i-a100-r-ccu.h | 18 + 10 files changed, 1804 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100.h create mode 100644 include/dt-bindings/clock/sun50i-a100-ccu.h create mode 100644 include/dt-bindings/clock/sun50i-a100-r-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-a100-ccu.h create mode 100644 include/dt-bindings/reset/sun50i-a100-r-ccu.h 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 + */ + +#include +#include +#include +#include + +#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 + */ + +#ifndef _CCU_SUN50I_A100_R_H +#define _CCU_SUN50I_A100_R_H + +#include +#include + +#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 + */ + +#include +#include +#include +#include +#include + +#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 + */ + +#ifndef _CCU_SUN50I_A100_H_ +#define _CCU_SUN50I_A100_H_ + +#include +#include + +#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/include/dt-bindings/clock/sun50i-a100-ccu.h b/include/dt-bindings/clock/sun50i-a100-ccu.h new file mode 100644 index 000000000000..28dc36e1a232 --- /dev/null +++ b/include/dt-bindings/clock/sun50i-a100-ccu.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2020 Yangtao Li + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_A100_H_ +#define _DT_BINDINGS_CLK_SUN50I_A100_H_ + +#define CLK_PLL_PERIPH0 3 + +#define CLK_CPUX 24 + +#define CLK_APB1 29 + +#define CLK_MBUS 31 +#define CLK_DE 32 +#define CLK_BUS_DE 33 +#define CLK_G2D 34 +#define CLK_BUS_G2D 35 +#define CLK_GPU 36 +#define CLK_BUS_GPU 37 +#define CLK_CE 38 +#define CLK_BUS_CE 39 +#define CLK_VE 40 +#define CLK_BUS_VE 41 +#define CLK_BUS_DMA 42 +#define CLK_BUS_MSGBOX 43 +#define CLK_BUS_SPINLOCK 44 +#define CLK_BUS_HSTIMER 45 +#define CLK_AVS 46 +#define CLK_BUS_DBG 47 +#define CLK_BUS_PSI 48 +#define CLK_BUS_PWM 49 +#define CLK_BUS_IOMMU 50 +#define CLK_MBUS_DMA 51 +#define CLK_MBUS_VE 52 +#define CLK_MBUS_CE 53 +#define CLK_MBUS_NAND 54 +#define CLK_MBUS_CSI 55 +#define CLK_MBUS_ISP 56 +#define CLK_MBUS_G2D 57 + +#define CLK_NAND0 59 +#define CLK_NAND1 60 +#define CLK_BUS_NAND 61 +#define CLK_MMC0 62 +#define CLK_MMC1 63 +#define CLK_MMC2 64 +#define CLK_MMC3 65 +#define CLK_BUS_MMC0 66 +#define CLK_BUS_MMC1 67 +#define CLK_BUS_MMC2 68 +#define CLK_BUS_UART0 69 +#define CLK_BUS_UART1 70 +#define CLK_BUS_UART2 71 +#define CLK_BUS_UART3 72 +#define CLK_BUS_UART4 73 +#define CLK_BUS_I2C0 74 +#define CLK_BUS_I2C1 75 +#define CLK_BUS_I2C2 76 +#define CLK_BUS_I2C3 77 +#define CLK_SPI0 78 +#define CLK_SPI1 79 +#define CLK_SPI2 80 +#define CLK_BUS_SPI0 81 +#define CLK_BUS_SPI1 82 +#define CLK_BUS_SPI2 83 +#define CLK_EMAC_25M 84 +#define CLK_BUS_EMAC 85 +#define CLK_IR_RX 86 +#define CLK_BUS_IR_RX 87 +#define CLK_IR_TX 88 +#define CLK_BUS_IR_TX 89 +#define CLK_BUS_GPADC 90 +#define CLK_BUS_THS 91 +#define CLK_I2S0 92 +#define CLK_I2S1 93 +#define CLK_I2S2 94 +#define CLK_I2S3 95 +#define CLK_BUS_I2S0 96 +#define CLK_BUS_I2S1 97 +#define CLK_BUS_I2S2 98 +#define CLK_BUS_I2S3 99 +#define CLK_SPDIF 100 +#define CLK_BUS_SPDIF 101 +#define CLK_DMIC 102 +#define CLK_BUS_DMIC 103 +#define CLK_AUDIO_DAC 104 +#define CLK_AUDIO_ADC 105 +#define CLK_AUDIO_4X 106 +#define CLK_BUS_AUDIO_CODEC 107 +#define CLK_USB_OHCI0 108 +#define CLK_USB_PHY0 109 +#define CLK_USB_OHCI1 110 +#define CLK_USB_PHY1 111 +#define CLK_BUS_OHCI0 112 +#define CLK_BUS_OHCI1 113 +#define CLK_BUS_EHCI0 114 +#define CLK_BUS_EHCI1 115 +#define CLK_BUS_OTG 116 +#define CLK_BUS_LRADC 117 +#define CLK_BUS_DPSS_TOP0 118 +#define CLK_BUS_DPSS_TOP1 119 +#define CLK_MIPI_DSI 120 +#define CLK_BUS_MIPI_DSI 121 +#define CLK_TCON_LCD 122 +#define CLK_BUS_TCON_LCD 123 +#define CLK_LEDC 124 +#define CLK_BUS_LEDC 125 +#define CLK_CSI_TOP 126 +#define CLK_CSI0_MCLK 127 +#define CLK_CSI1_MCLK 128 +#define CLK_BUS_CSI 129 +#define CLK_CSI_ISP 130 + +#endif /* _DT_BINDINGS_CLK_SUN50I_A100_H_ */ diff --git a/include/dt-bindings/clock/sun50i-a100-r-ccu.h b/include/dt-bindings/clock/sun50i-a100-r-ccu.h new file mode 100644 index 000000000000..07312e7264fb --- /dev/null +++ b/include/dt-bindings/clock/sun50i-a100-r-ccu.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Yangtao Li + */ + +#ifndef _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_ +#define _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_ + +#define CLK_R_APB1 2 + +#define CLK_R_APB1_TIMER 4 +#define CLK_R_APB1_TWD 5 +#define CLK_R_APB1_PWM 6 +#define CLK_R_APB1_BUS_PWM 7 +#define CLK_R_APB1_PPU 8 +#define CLK_R_APB2_UART 9 +#define CLK_R_APB2_I2C0 10 +#define CLK_R_APB2_I2C1 11 +#define CLK_R_APB1_IR 12 +#define CLK_R_APB1_BUS_IR 13 +#define CLK_R_AHB_BUS_RTC 14 + +#endif /* _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_ */ diff --git a/include/dt-bindings/reset/sun50i-a100-ccu.h b/include/dt-bindings/reset/sun50i-a100-ccu.h new file mode 100644 index 000000000000..55c0ada99885 --- /dev/null +++ b/include/dt-bindings/reset/sun50i-a100-ccu.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2020 Yangtao Li + */ + +#ifndef _DT_BINDINGS_RESET_SUN50I_A100_H_ +#define _DT_BINDINGS_RESET_SUN50I_A100_H_ + +#define RST_MBUS 0 +#define RST_BUS_DE 1 +#define RST_BUS_G2D 2 +#define RST_BUS_GPU 3 +#define RST_BUS_CE 4 +#define RST_BUS_VE 5 +#define RST_BUS_DMA 6 +#define RST_BUS_MSGBOX 7 +#define RST_BUS_SPINLOCK 8 +#define RST_BUS_HSTIMER 9 +#define RST_BUS_DBG 10 +#define RST_BUS_PSI 11 +#define RST_BUS_PWM 12 +#define RST_BUS_DRAM 13 +#define RST_BUS_NAND 14 +#define RST_BUS_MMC0 15 +#define RST_BUS_MMC1 16 +#define RST_BUS_MMC2 17 +#define RST_BUS_UART0 18 +#define RST_BUS_UART1 19 +#define RST_BUS_UART2 20 +#define RST_BUS_UART3 21 +#define RST_BUS_UART4 22 +#define RST_BUS_I2C0 23 +#define RST_BUS_I2C1 24 +#define RST_BUS_I2C2 25 +#define RST_BUS_I2C3 26 +#define RST_BUS_SPI0 27 +#define RST_BUS_SPI1 28 +#define RST_BUS_SPI2 29 +#define RST_BUS_EMAC 30 +#define RST_BUS_IR_RX 31 +#define RST_BUS_IR_TX 32 +#define RST_BUS_GPADC 33 +#define RST_BUS_THS 34 +#define RST_BUS_I2S0 35 +#define RST_BUS_I2S1 36 +#define RST_BUS_I2S2 37 +#define RST_BUS_I2S3 38 +#define RST_BUS_SPDIF 39 +#define RST_BUS_DMIC 40 +#define RST_BUS_AUDIO_CODEC 41 +#define RST_USB_PHY0 42 +#define RST_USB_PHY1 43 +#define RST_BUS_OHCI0 44 +#define RST_BUS_OHCI1 45 +#define RST_BUS_EHCI0 46 +#define RST_BUS_EHCI1 47 +#define RST_BUS_OTG 48 +#define RST_BUS_LRADC 49 +#define RST_BUS_DPSS_TOP0 50 +#define RST_BUS_DPSS_TOP1 51 +#define RST_BUS_MIPI_DSI 52 +#define RST_BUS_TCON_LCD 53 +#define RST_BUS_LVDS 54 +#define RST_BUS_LEDC 55 +#define RST_BUS_CSI 56 +#define RST_BUS_CSI_ISP 57 + +#endif /* _DT_BINDINGS_RESET_SUN50I_A100_H_ */ diff --git a/include/dt-bindings/reset/sun50i-a100-r-ccu.h b/include/dt-bindings/reset/sun50i-a100-r-ccu.h new file mode 100644 index 000000000000..737bf6f66626 --- /dev/null +++ b/include/dt-bindings/reset/sun50i-a100-r-ccu.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2020 Yangtao Li + */ + +#ifndef _DT_BINDINGS_RST_SUN50I_A100_R_CCU_H_ +#define _DT_BINDINGS_RST_SUN50I_A100_R_CCU_H_ + +#define RST_R_APB1_TIMER 0 +#define RST_R_APB1_BUS_PWM 1 +#define RST_R_APB1_PPU 2 +#define RST_R_APB2_UART 3 +#define RST_R_APB2_I2C0 4 +#define RST_R_APB2_I2C1 5 +#define RST_R_APB1_BUS_IR 6 +#define RST_R_AHB_BUS_RTC 7 + +#endif /* _DT_BINDINGS_RST_SUN50I_A100_R_CCU_H_ */ From a3ba99a24b36bc4eee5413a820e2c4f3d81593fa Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 25 Aug 2020 15:10:49 +0200 Subject: [PATCH 06/21] clk: sunxi-ng: sun8i: r40: Use sigma delta modulation for audio PLL Audio cores need specific clock rates which can't be simply obtained by adjusting integer multipliers and dividers. HW for such cases supports delta-sigma modulation which enables fractional multipliers. Port H3 delta-sigma table to R40. They have identical audio PLLs. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20200825131049.1277596-1-jernej.skrabec@siol.net --- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 37 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) 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); From 2c4e80e06790cb49ad2603855d30c5aac2209c47 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 28 Aug 2020 17:52:05 +0200 Subject: [PATCH 07/21] clk: meson: g12a: mark fclk_div2 as critical On Amlogic Meson G12b platform, similar to fclk_div3, the fclk_div2 seems to be necessary for the system to operate correctly as well. Typically, the clock also gets chosen by the eMMC peripheral. This probably masked the problem so far. However, when booting from a SD card the clock seems to get disabled which leads to a system freeze. Let's mark this clock as critical, fixing boot from SD card on G12b platforms. Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") Signed-off-by: Stefan Agner Signed-off-by: Jerome Brunet Tested-by: Anand Moon Cc: Marek Szyprowski Link: https://lore.kernel.org/r/577e0129e8ee93972d92f13187ff4e4286182f67.1598629915.git.stefan@agner.ch --- drivers/clk/meson/g12a.c | 11 +++++++++++ 1 file changed, 11 insertions(+) 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, }, }; From 7b5c5720a3689c2c16968ee276b7c47edb64ce0f Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 28 Aug 2020 17:47:35 +0200 Subject: [PATCH 08/21] clk: meson: make shipped controller configurable Add the necessary bits so unnecessary amlogic clock controllers can be compiled out. This allows to save a few kB when necessary. Signed-off-by: Jerome Brunet Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20200828154735.435374-1-jbrunet@baylibre.com --- drivers/clk/meson/Kconfig | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) 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 From 0212a0483b0a36cc94cfab882b3edbb41fcfe1cd Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 7 Aug 2020 15:31:43 +0200 Subject: [PATCH 09/21] clk: samsung: Keep top BPLL mux on Exynos542x enabled BPLL clock must not be disabled because it is needed for proper DRAM operation. This is normally handled by respective memory devfreq driver, but when that driver is not yet probed or its probe has been deferred the clock might get disabled what causes board hang. Fix this by calling clk_prepare_enable() directly from the clock provider driver. Cc: stable@vger.kernel.org Signed-off-by: Marek Szyprowski Reviewed-by: Lukasz Luba Tested-by: Lukasz Luba Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200807133143.22748-1-m.szyprowski@samsung.com Fixes: 6e7674c3c6df ("memory: Add DMC driver for Exynos5422") Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5420.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index fea33399a632..bd620876544d 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1655,6 +1655,11 @@ static void __init exynos5x_clk_init(struct device_node *np, * main G3D clock enablement status. */ clk_prepare_enable(__clk_lookup("mout_sw_aclk_g3d")); + /* + * Keep top BPLL mux enabled permanently to ensure that DRAM operates + * properly. + */ + clk_prepare_enable(__clk_lookup("mout_bpll")); samsung_clk_of_add_provider(np, ctx); } From 3f1cc53b5f6f26e80e3176936714ec5dcab74244 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 11 Aug 2020 17:12:50 +0200 Subject: [PATCH 10/21] clk: samsung: exynos5420: Add definition of clock ID for mout_sw_aclk_g3d This patch adds ID for the mout_sw_aclk_g3d (SW_CLKMUX_ACLK_G3D) clock, mostly for internal use in the CMU driver. It will allow to avoid the __clk_lookup() call when setting up the clock during the clock provider initialization. Link: https://lore.kernel.org/r/20200811151251.31613-1-s.nawrocki@samsung.com Signed-off-by: Sylwester Nawrocki --- include/dt-bindings/clock/exynos5420.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 02d5ac469a3d..ff917c818f05 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -230,6 +230,7 @@ #define CLK_MOUT_USER_MAU_EPLL 659 #define CLK_MOUT_SCLK_SPLL 660 #define CLK_MOUT_MX_MSPLL_CCORE_PHY 661 +#define CLK_MOUT_SW_ACLK_G3D 662 /* divider clocks */ #define CLK_DOUT_PIXEL 768 From 8b066520ff7e5d8e843f4e405da0069636980666 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 11 Aug 2020 17:12:51 +0200 Subject: [PATCH 11/21] clk: samsung: exynos5420: Avoid __clk_lookup() calls when enabling clocks This patch adds a clk ID to the mout_sw_aclk_g3d clk definition so related clk pointer gets cached in the driver's private data and can be used later instead of a __clk_lookup() call. With that we have all clocks used in the clk_prepare_enable() calls in the clk provider init callback cached in clk_data.hws[] and we can reference the clk pointers directly rather than using __clk_lookup() with global names. Link: https://lore.kernel.org/r/20200811151251.31613-2-s.nawrocki@samsung.com Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5420.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index bd620876544d..f76ebd6b547f 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -712,8 +712,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 +1560,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); @@ -1649,17 +1650,18 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5x_subcmus); } + hws = ctx->clk_data.hws; /* * Keep top part of G3D clock path enabled permanently to ensure * 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(__clk_lookup("mout_bpll")); + clk_prepare_enable(hws[CLK_MOUT_BPLL]->clk); samsung_clk_of_add_provider(np, ctx); } From f493602db56beee1514b37180599a1f3f66f816e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 26 Aug 2020 19:15:27 +0200 Subject: [PATCH 12/21] clk: samsung: Add clk ID definitions for the CPU parent clocks Add clock ID definitions for the CPU parent clocks for SoCs which don't have such definitions yet. This will allow us to reference the parent clocks directly by cached struct clk_hw pointers in the clock provider, rather than doing clk lookup by name. Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Acked-by: Rob Herring Link: https://lore.kernel.org/r/20200826171529.23618-1-s.nawrocki@samsung.com Signed-off-by: Sylwester Nawrocki --- include/dt-bindings/clock/exynos5250.h | 4 +++- include/dt-bindings/clock/exynos5420.h | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/exynos5250.h b/include/dt-bindings/clock/exynos5250.h index bc8a3c53a54b..e259cc01f22f 100644 --- a/include/dt-bindings/clock/exynos5250.h +++ b/include/dt-bindings/clock/exynos5250.h @@ -172,8 +172,10 @@ #define CLK_MOUT_GPLL 1025 #define CLK_MOUT_ACLK200_DISP1_SUB 1026 #define CLK_MOUT_ACLK300_DISP1_SUB 1027 +#define CLK_MOUT_APLL 1028 +#define CLK_MOUT_MPLL 1029 /* must be greater than maximal clock id */ -#define CLK_NR_CLKS 1028 +#define CLK_NR_CLKS 1030 #endif /* _DT_BINDINGS_CLOCK_EXYNOS_5250_H */ diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index ff917c818f05..9fffc6ceaadd 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h @@ -231,6 +231,11 @@ #define CLK_MOUT_SCLK_SPLL 660 #define CLK_MOUT_MX_MSPLL_CCORE_PHY 661 #define CLK_MOUT_SW_ACLK_G3D 662 +#define CLK_MOUT_APLL 663 +#define CLK_MOUT_MSPLL_CPU 664 +#define CLK_MOUT_KPLL 665 +#define CLK_MOUT_MSPLL_KFC 666 + /* divider clocks */ #define CLK_DOUT_PIXEL 768 From 1f6e17d20245e86678c75ed99ce115f46cd3410f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 26 Aug 2020 19:15:28 +0200 Subject: [PATCH 13/21] clk: samsung: exynos5420/5250: Add IDs to the CPU parent clk definitions Use non-zero clock IDs in definitions of the CPU parent clocks for exynos5420, exynos5250 SoCs. This will allow us to reference the parent clocks directly in the driver by cached struct clk_hw pointers, rather than doing clk lookup by name. Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20200826171529.23618-2-s.nawrocki@samsung.com Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5250.c | 4 ++-- drivers/clk/samsung/clk-exynos5420.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 931c70a4da19..7bcff76ad395 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 diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index f76ebd6b547f..d07cee226dc2 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), From ff8e0ff9b99643a32f7e33a96867e76d0fa10f76 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 26 Aug 2020 19:15:29 +0200 Subject: [PATCH 14/21] clk: samsung: Use cached clk_hws instead of __clk_lookup() calls For the CPU clock registration two parent clocks are required, these are now being passed as struct clk_hw pointers, rather than by the global scope names. That allows us to avoid __clk_lookup() calls and simplifies a bit the CPU clock registration function. While at it drop unneeded extern keyword in the function declaration. Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20200826171529.23618-3-s.nawrocki@samsung.com Reported-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-cpu.c | 37 +++++++++++----------------- drivers/clk/samsung/clk-cpu.h | 6 ++--- drivers/clk/samsung/clk-exynos3250.c | 6 +++-- drivers/clk/samsung/clk-exynos4.c | 7 ++++-- drivers/clk/samsung/clk-exynos5250.c | 4 ++- drivers/clk/samsung/clk-exynos5420.c | 8 +++--- drivers/clk/samsung/clk-exynos5433.c | 10 ++++++-- 7 files changed, 42 insertions(+), 36 deletions(-) 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 7bcff76ad395..06588fab408a 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -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 d07cee226dc2..3ccd4eabd2a6 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1574,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), @@ -1625,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, @@ -1651,7 +1652,6 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5x_subcmus); } - hws = ctx->clk_data.hws; /* * Keep top part of G3D clock path enabled permanently to ensure * that the internal busses get their clock regardless of the 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); From 533852d71840a5f8b0cfa6ad8027e6493ea0cc7b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 22:35:57 +0200 Subject: [PATCH 15/21] clk: s2mps11: initialize driver via module_platform_driver The driver was using subsys_initcall() because in old times deferred probe was not supported everywhere and specific ordering was needed. Since probe deferral works fine and specific ordering is discouraged (hides dependencies between drivers and couples their boot order), the driver can be converted to regular module_platform_driver. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200921203558.19554-1-krzk@kernel.org Tested-by: Marek Szyprowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-s2mps11.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) 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 "); From 52ba4fa40fb314e4d342d0f2b09c3fa525b0ad5b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Sep 2020 18:17:36 +0200 Subject: [PATCH 16/21] clk: fixed: add missing kerneldoc Add missing kerneldoc to fix compile warnings like: drivers/clk/clk-fixed-factor.c:211: warning: Function parameter or member 'node' not described in 'of_fixed_factor_clk_setup' Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200916161740.14173-2-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-factor.c | 1 + drivers/clk/clk-fixed-rate.c | 1 + 2 files changed, 2 insertions(+) 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) { From faeda014b49ece0a175215ae41f4c38786386ca0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Sep 2020 18:17:37 +0200 Subject: [PATCH 17/21] clk: davinci: add missing kerneldoc Add missing kerneldoc to fix compile warning: drivers/clk/davinci/da8xx-cfgchip.c:578: warning: Function parameter or member 'dev' not described in 'da8xx_cfgchip_register_usb1_clk48' Signed-off-by: Krzysztof Kozlowski Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20200916161740.14173-3-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/davinci/da8xx-cfgchip.c | 1 + 1 file changed, 1 insertion(+) 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 * From 425c23d382abb028629222c3cce5a7ea7e858618 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Sep 2020 18:17:35 +0200 Subject: [PATCH 18/21] clk: at91: drop unused at91sam9g45_pcr_layout The at91sam9g45_pcr_layout is not used so drop it to fix build warning: drivers/clk/at91/at91sam9g45.c:49:36: warning: 'at91sam9g45_pcr_layout' defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200916161740.14173-1-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/at91/at91sam9g45.c | 7 ------- 1 file changed, 7 deletions(-) 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; From f5e75b4aaec42c66b18fdfa96b4041e8af4e7b31 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Sep 2020 18:17:38 +0200 Subject: [PATCH 19/21] clk: mmp: pxa1928: drop unused 'clk' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'clk' is assigned but never read: drivers/clk/mmp/clk-of-pxa1928.c: In function ‘pxa1928_pll_init’: drivers/clk/mmp/clk-of-pxa1928.c:71:14: warning: variable ‘clk’ set but not used [-Wunused-but-set-variable] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200916161740.14173-4-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-pxa1928.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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, From 84afc9ecf4e4f51ccf9ca3ab2da49a519b0eadcc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 16 Sep 2020 18:17:39 +0200 Subject: [PATCH 20/21] clk: si5341: drop unused 'err' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'err' is assigned but never read: /drivers/clk/clk-si5341.c: In function ‘si5341_output_get_parent’: drivers/clk/clk-si5341.c:886:6: warning: variable ‘err’ set but not used [-Wunused-but-set-variable] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200916161740.14173-5-krzk@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5341.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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; } From b10f22493512585b329fd1ed436f9c310aaf36ce Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 15 Sep 2020 10:09:50 +0800 Subject: [PATCH 21/21] clk: socfpga: agilex: Remove unused variable 'cntr_mux' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/clk/socfpga/clk-agilex.c:24:37: warning: ‘cntr_mux’ defined but not used [-Wunused-const-variable=] static const struct clk_parent_data cntr_mux[] = { ^~~~~~~~ There is no caller in tree, so can remove it. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20200915020950.4688-1-yuehaibing@huawei.com Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-agilex.c | 13 ------------- 1 file changed, 13 deletions(-) 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", },