From 3d5155eaadaf512808cb57ec0c7db7bd4cc1ef67 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 17 May 2018 11:04:15 +0200 Subject: [PATCH 01/85] clk: renesas: r8a7795: Add CR clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the CR core clock, which is used by the Secure Engine (SCEG). Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Reviewed-by: Simon Horman Tested-by: Gilad Ben-Yossef --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 775b0ceaa337..e5b186566c09 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -103,6 +103,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_SDSRC, 0x26c), DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cr", R8A7795_CLK_CR, CLK_PLL1_DIV4, 2, 1), DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244), From 46f3bb5fb944089aaa8130a80f5b7df877c58554 Mon Sep 17 00:00:00 2001 From: Gilad Ben-Yossef Date: Thu, 24 May 2018 15:19:09 +0100 Subject: [PATCH 02/85] clk: renesas: r8a7795: Add CCREE clock This patch adds the clock used by the CryptoCell 630p instance in the SoC. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index e5b186566c09..a85dd50e8911 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -133,6 +133,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S0D3), DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S0D3), DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S0D3), + DEF_MOD("sceg-pub", 229, R8A7795_CLK_CR), DEF_MOD("cmt3", 300, R8A7795_CLK_R), DEF_MOD("cmt2", 301, R8A7795_CLK_R), DEF_MOD("cmt1", 302, R8A7795_CLK_R), From 04cdd5af51c610ddc7ff4881790a830a6a97d3fd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 19 Jun 2018 15:40:50 +0200 Subject: [PATCH 03/85] clk: qcom: drop CLK_SET_RATE_GATE from sdc clocks the mmci driver (drivers/mmc/host/mmci.c) does the following sequence: * clk_prepare_enable() * clk_set_rate() on SDCx_clk which is a children of SDCx_src. SDCx_src has CLK_SET_RATE_GATE so this sequence should not be allowed but this was not enforced. IOW, the flag is ignored. Dropping the flag won't change anything to the current behaviour of the platform. CLK_SET_RATE_GATE is being fixed and enforced now. If the flag was kept, the mmci driver would receive -EBUSY when calling clk_set_rate() Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/20180619134051.16726-2-jbrunet@baylibre.com --- drivers/clk/qcom/gcc-ipq806x.c | 3 --- drivers/clk/qcom/gcc-mdm9615.c | 2 -- drivers/clk/qcom/gcc-msm8660.c | 5 ----- drivers/clk/qcom/gcc-msm8960.c | 5 ----- 4 files changed, 15 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 28eb200d0f1e..5f61225657ab 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -1220,7 +1220,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1269,7 +1268,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1353,7 +1351,6 @@ static struct clk_rcg tsif_ref_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index b99dd406e907..849046fbed6d 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -947,7 +947,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -996,7 +995,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index c347a0d44bc8..7e930e25c79f 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -1558,7 +1558,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1607,7 +1606,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1656,7 +1654,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1705,7 +1702,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1754,7 +1750,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index eb551c75fba6..fd495e0471bb 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -1628,7 +1628,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1677,7 +1676,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1726,7 +1724,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1775,7 +1772,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1824,7 +1820,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; From 9461f7b33d11cbbf5ce79c3c03d0da9d42dfce92 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 19 Jun 2018 15:40:51 +0200 Subject: [PATCH 04/85] clk: fix CLK_SET_RATE_GATE with clock rate protection CLK_SET_RATE_GATE should prevent any operation which may result in a rate change or glitch while the clock is prepared/enabled. IOW, the following sequence is not allowed anymore with CLK_SET_RATE_GATE: * clk_get() * clk_prepare_enable() * clk_get_rate() * clk_set_rate() At the moment this is enforced on the leaf clock of the operation, not along the tree. This problematic because, if a PLL has the CLK_RATE_GATE, it won't be enforced if the clk_set_rate() is called on its child clocks. Using clock rate protection, we can now enforce CLK_SET_RATE_GATE along the clock tree Acked-by: Linus Walleij Tested-by: Quentin Schulz Tested-by: Maxime Ripard Signed-off-by: Jerome Brunet Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/20180619134051.16726-3-jbrunet@baylibre.com --- drivers/clk/clk.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9760b526ca31..97c09243fb21 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -691,6 +691,9 @@ static void clk_core_unprepare(struct clk_core *core) "Unpreparing critical %s\n", core->name)) return; + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_unprotect(core); + if (--core->prepare_count > 0) return; @@ -765,6 +768,16 @@ static int clk_core_prepare(struct clk_core *core) core->prepare_count++; + /* + * CLK_SET_RATE_GATE is a special case of clock protection + * Instead of a consumer claiming exclusive rate control, it is + * actually the provider which prevents any consumer from making any + * operation which could result in a rate change or rate glitch while + * the clock is prepared. + */ + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_protect(core); + return 0; unprepare: clk_core_unprepare(core->parent); @@ -1888,9 +1901,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (clk_core_rate_is_protected(core)) return -EBUSY; - if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) - return -EBUSY; - /* calculate new rates and get the topmost changed clock */ top = clk_calc_new_rates(core, req_rate); if (!top) From 372401efd9eeee24701848874ecb9845524013ee Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:56 +0200 Subject: [PATCH 05/85] dt-bindings: clock: add meson axg audio clock controller bindings Export the clock ids dt-bindings usable by the consumers of the clock controller and add the documentation for the device tree bindings of the audio clock controller of the A113 based SoCs. Acked-by: Neil Armstrong Reviewed-by: Rob Herring Signed-off-by: Jerome Brunet --- .../bindings/clock/amlogic,axg-audio-clkc.txt | 56 +++++++++++ include/dt-bindings/clock/axg-audio-clkc.h | 94 +++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt create mode 100644 include/dt-bindings/clock/axg-audio-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt new file mode 100644 index 000000000000..61777ad24f61 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt @@ -0,0 +1,56 @@ +* Amlogic AXG Audio Clock Controllers + +The Amlogic AXG audio clock controller generates and supplies clock to the +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm +devices. + +Required Properties: + +- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D +- reg : physical base address of the clock controller and length of + memory mapped region. +- clocks : a list of phandle + clock-specifier pairs for the clocks listed + in clock-names. +- clock-names : must contain the following: + * "pclk" - Main peripheral bus clock + may contain the following: + * "mst_in[0-7]" - 8 input plls to generate clock signals + * "slv_sclk[0-9]" - 10 slave bit clocks provided by external + components. + * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external + components. +- resets : phandle of the internal reset line +- #clock-cells : should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be +used in device tree sources. + +Example: + +clkc_audio: clock-controller@0 { + compatible = "amlogic,axg-audio-clkc"; + reg = <0x0 0x0 0x0 0xb4>; + #clock-cells = <1>; + + clocks = <&clkc CLKID_AUDIO>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL3>, + <&clkc CLKID_HIFI_PLL>, + <&clkc CLKID_FCLK_DIV3>, + <&clkc CLKID_FCLK_DIV4>, + <&clkc CLKID_GP0_PLL>; + clock-names = "pclk", + "mst_in0", + "mst_in1", + "mst_in2", + "mst_in3", + "mst_in4", + "mst_in5", + "mst_in6", + "mst_in7"; + resets = <&reset RESET_AUDIO>; +}; diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h new file mode 100644 index 000000000000..fd9c362099d9 --- /dev/null +++ b/include/dt-bindings/clock/axg-audio-clkc.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2018 Baylibre SAS. + * Author: Jerome Brunet + */ + +#ifndef __AXG_AUDIO_CLKC_BINDINGS_H +#define __AXG_AUDIO_CLKC_BINDINGS_H + +#define AUD_CLKID_SLV_SCLK0 9 +#define AUD_CLKID_SLV_SCLK1 10 +#define AUD_CLKID_SLV_SCLK2 11 +#define AUD_CLKID_SLV_SCLK3 12 +#define AUD_CLKID_SLV_SCLK4 13 +#define AUD_CLKID_SLV_SCLK5 14 +#define AUD_CLKID_SLV_SCLK6 15 +#define AUD_CLKID_SLV_SCLK7 16 +#define AUD_CLKID_SLV_SCLK8 17 +#define AUD_CLKID_SLV_SCLK9 18 +#define AUD_CLKID_SLV_LRCLK0 19 +#define AUD_CLKID_SLV_LRCLK1 20 +#define AUD_CLKID_SLV_LRCLK2 21 +#define AUD_CLKID_SLV_LRCLK3 22 +#define AUD_CLKID_SLV_LRCLK4 23 +#define AUD_CLKID_SLV_LRCLK5 24 +#define AUD_CLKID_SLV_LRCLK6 25 +#define AUD_CLKID_SLV_LRCLK7 26 +#define AUD_CLKID_SLV_LRCLK8 27 +#define AUD_CLKID_SLV_LRCLK9 28 +#define AUD_CLKID_DDR_ARB 29 +#define AUD_CLKID_PDM 30 +#define AUD_CLKID_TDMIN_A 31 +#define AUD_CLKID_TDMIN_B 32 +#define AUD_CLKID_TDMIN_C 33 +#define AUD_CLKID_TDMIN_LB 34 +#define AUD_CLKID_TDMOUT_A 35 +#define AUD_CLKID_TDMOUT_B 36 +#define AUD_CLKID_TDMOUT_C 37 +#define AUD_CLKID_FRDDR_A 38 +#define AUD_CLKID_FRDDR_B 39 +#define AUD_CLKID_FRDDR_C 40 +#define AUD_CLKID_TODDR_A 41 +#define AUD_CLKID_TODDR_B 42 +#define AUD_CLKID_TODDR_C 43 +#define AUD_CLKID_LOOPBACK 44 +#define AUD_CLKID_SPDIFIN 45 +#define AUD_CLKID_SPDIFOUT 46 +#define AUD_CLKID_RESAMPLE 47 +#define AUD_CLKID_POWER_DETECT 48 +#define AUD_CLKID_MST_A_MCLK 49 +#define AUD_CLKID_MST_B_MCLK 50 +#define AUD_CLKID_MST_C_MCLK 51 +#define AUD_CLKID_MST_D_MCLK 52 +#define AUD_CLKID_MST_E_MCLK 53 +#define AUD_CLKID_MST_F_MCLK 54 +#define AUD_CLKID_SPDIFOUT_CLK 55 +#define AUD_CLKID_SPDIFIN_CLK 56 +#define AUD_CLKID_PDM_DCLK 57 +#define AUD_CLKID_PDM_SYSCLK 58 +#define AUD_CLKID_MST_A_SCLK 79 +#define AUD_CLKID_MST_B_SCLK 80 +#define AUD_CLKID_MST_C_SCLK 81 +#define AUD_CLKID_MST_D_SCLK 82 +#define AUD_CLKID_MST_E_SCLK 83 +#define AUD_CLKID_MST_F_SCLK 84 +#define AUD_CLKID_MST_A_LRCLK 86 +#define AUD_CLKID_MST_B_LRCLK 87 +#define AUD_CLKID_MST_C_LRCLK 88 +#define AUD_CLKID_MST_D_LRCLK 89 +#define AUD_CLKID_MST_E_LRCLK 90 +#define AUD_CLKID_MST_F_LRCLK 91 +#define AUD_CLKID_TDMIN_A_SCLK_SEL 116 +#define AUD_CLKID_TDMIN_B_SCLK_SEL 117 +#define AUD_CLKID_TDMIN_C_SCLK_SEL 118 +#define AUD_CLKID_TDMIN_LB_SCLK_SEL 119 +#define AUD_CLKID_TDMOUT_A_SCLK_SEL 120 +#define AUD_CLKID_TDMOUT_B_SCLK_SEL 121 +#define AUD_CLKID_TDMOUT_C_SCLK_SEL 122 +#define AUD_CLKID_TDMIN_A_SCLK 123 +#define AUD_CLKID_TDMIN_B_SCLK 124 +#define AUD_CLKID_TDMIN_C_SCLK 125 +#define AUD_CLKID_TDMIN_LB_SCLK 126 +#define AUD_CLKID_TDMOUT_A_SCLK 127 +#define AUD_CLKID_TDMOUT_B_SCLK 128 +#define AUD_CLKID_TDMOUT_C_SCLK 129 +#define AUD_CLKID_TDMIN_A_LRCLK 130 +#define AUD_CLKID_TDMIN_B_LRCLK 131 +#define AUD_CLKID_TDMIN_C_LRCLK 132 +#define AUD_CLKID_TDMIN_LB_LRCLK 133 +#define AUD_CLKID_TDMOUT_A_LRCLK 134 +#define AUD_CLKID_TDMOUT_B_LRCLK 135 +#define AUD_CLKID_TDMOUT_C_LRCLK 136 + +#endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ From d467239f37c4e49158e0569a26c6a9c365ec5b61 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Thu, 14 Jun 2018 11:56:30 +0100 Subject: [PATCH 06/85] dt-bindings: clock: Add the r9a06g032-sysctrl.h file This adds the constants necessary to use the renesas,r9a06g032-sysctrl node. Signed-off-by: Michel Pollet Reviewed-by: Rob Herring Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/r9a06g032-sysctrl.h | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 include/dt-bindings/clock/r9a06g032-sysctrl.h diff --git a/include/dt-bindings/clock/r9a06g032-sysctrl.h b/include/dt-bindings/clock/r9a06g032-sysctrl.h new file mode 100644 index 000000000000..90c0f3dc1ba1 --- /dev/null +++ b/include/dt-bindings/clock/r9a06g032-sysctrl.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R9A06G032 sysctrl IDs + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet , + */ + +#ifndef __DT_BINDINGS_R9A06G032_SYSCTRL_H__ +#define __DT_BINDINGS_R9A06G032_SYSCTRL_H__ + +#define R9A06G032_CLK_PLL_USB 1 +#define R9A06G032_CLK_48 1 /* AKA CLK_PLL_USB */ +#define R9A06G032_MSEBIS_CLK 3 /* AKA CLKOUT_D16 */ +#define R9A06G032_MSEBIM_CLK 3 /* AKA CLKOUT_D16 */ +#define R9A06G032_CLK_DDRPHY_PLLCLK 5 /* AKA CLKOUT_D1OR2 */ +#define R9A06G032_CLK50 6 /* AKA CLKOUT_D20 */ +#define R9A06G032_CLK25 7 /* AKA CLKOUT_D40 */ +#define R9A06G032_CLK125 9 /* AKA CLKOUT_D8 */ +#define R9A06G032_CLK_P5_PG1 17 /* AKA DIV_P5_PG */ +#define R9A06G032_CLK_REF_SYNC 21 /* AKA DIV_REF_SYNC */ +#define R9A06G032_CLK_25_PG4 26 +#define R9A06G032_CLK_25_PG5 27 +#define R9A06G032_CLK_25_PG6 28 +#define R9A06G032_CLK_25_PG7 29 +#define R9A06G032_CLK_25_PG8 30 +#define R9A06G032_CLK_ADC 31 +#define R9A06G032_CLK_ECAT100 32 +#define R9A06G032_CLK_HSR100 33 +#define R9A06G032_CLK_I2C0 34 +#define R9A06G032_CLK_I2C1 35 +#define R9A06G032_CLK_MII_REF 36 +#define R9A06G032_CLK_NAND 37 +#define R9A06G032_CLK_NOUSBP2_PG6 38 +#define R9A06G032_CLK_P1_PG2 39 +#define R9A06G032_CLK_P1_PG3 40 +#define R9A06G032_CLK_P1_PG4 41 +#define R9A06G032_CLK_P4_PG3 42 +#define R9A06G032_CLK_P4_PG4 43 +#define R9A06G032_CLK_P6_PG1 44 +#define R9A06G032_CLK_P6_PG2 45 +#define R9A06G032_CLK_P6_PG3 46 +#define R9A06G032_CLK_P6_PG4 47 +#define R9A06G032_CLK_PCI_USB 48 +#define R9A06G032_CLK_QSPI0 49 +#define R9A06G032_CLK_QSPI1 50 +#define R9A06G032_CLK_RGMII_REF 51 +#define R9A06G032_CLK_RMII_REF 52 +#define R9A06G032_CLK_SDIO0 53 +#define R9A06G032_CLK_SDIO1 54 +#define R9A06G032_CLK_SERCOS100 55 +#define R9A06G032_CLK_SLCD 56 +#define R9A06G032_CLK_SPI0 57 +#define R9A06G032_CLK_SPI1 58 +#define R9A06G032_CLK_SPI2 59 +#define R9A06G032_CLK_SPI3 60 +#define R9A06G032_CLK_SPI4 61 +#define R9A06G032_CLK_SPI5 62 +#define R9A06G032_CLK_SWITCH 63 +#define R9A06G032_HCLK_ECAT125 65 +#define R9A06G032_HCLK_PINCONFIG 66 +#define R9A06G032_HCLK_SERCOS 67 +#define R9A06G032_HCLK_SGPIO2 68 +#define R9A06G032_HCLK_SGPIO3 69 +#define R9A06G032_HCLK_SGPIO4 70 +#define R9A06G032_HCLK_TIMER0 71 +#define R9A06G032_HCLK_TIMER1 72 +#define R9A06G032_HCLK_USBF 73 +#define R9A06G032_HCLK_USBH 74 +#define R9A06G032_HCLK_USBPM 75 +#define R9A06G032_CLK_48_PG_F 76 +#define R9A06G032_CLK_48_PG4 77 +#define R9A06G032_CLK_DDRPHY_PCLK 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_FW 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_CRYPTO 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_A7MP 84 /* AKA DIV_CA7 */ +#define R9A06G032_HCLK_CAN0 85 +#define R9A06G032_HCLK_CAN1 86 +#define R9A06G032_HCLK_DELTASIGMA 87 +#define R9A06G032_HCLK_PWMPTO 88 +#define R9A06G032_HCLK_RSV 89 +#define R9A06G032_HCLK_SGPIO0 90 +#define R9A06G032_HCLK_SGPIO1 91 +#define R9A06G032_RTOS_MDC 92 +#define R9A06G032_CLK_CM3 93 +#define R9A06G032_CLK_DDRC 94 +#define R9A06G032_CLK_ECAT25 95 +#define R9A06G032_CLK_HSR50 96 +#define R9A06G032_CLK_HW_RTOS 97 +#define R9A06G032_CLK_SERCOS50 98 +#define R9A06G032_HCLK_ADC 99 +#define R9A06G032_HCLK_CM3 100 +#define R9A06G032_HCLK_CRYPTO_EIP150 101 +#define R9A06G032_HCLK_CRYPTO_EIP93 102 +#define R9A06G032_HCLK_DDRC 103 +#define R9A06G032_HCLK_DMA0 104 +#define R9A06G032_HCLK_DMA1 105 +#define R9A06G032_HCLK_GMAC0 106 +#define R9A06G032_HCLK_GMAC1 107 +#define R9A06G032_HCLK_GPIO0 108 +#define R9A06G032_HCLK_GPIO1 109 +#define R9A06G032_HCLK_GPIO2 110 +#define R9A06G032_HCLK_HSR 111 +#define R9A06G032_HCLK_I2C0 112 +#define R9A06G032_HCLK_I2C1 113 +#define R9A06G032_HCLK_LCD 114 +#define R9A06G032_HCLK_MSEBI_M 115 +#define R9A06G032_HCLK_MSEBI_S 116 +#define R9A06G032_HCLK_NAND 117 +#define R9A06G032_HCLK_PG_I 118 +#define R9A06G032_HCLK_PG19 119 +#define R9A06G032_HCLK_PG20 120 +#define R9A06G032_HCLK_PG3 121 +#define R9A06G032_HCLK_PG4 122 +#define R9A06G032_HCLK_QSPI0 123 +#define R9A06G032_HCLK_QSPI1 124 +#define R9A06G032_HCLK_ROM 125 +#define R9A06G032_HCLK_RTC 126 +#define R9A06G032_HCLK_SDIO0 127 +#define R9A06G032_HCLK_SDIO1 128 +#define R9A06G032_HCLK_SEMAP 129 +#define R9A06G032_HCLK_SPI0 130 +#define R9A06G032_HCLK_SPI1 131 +#define R9A06G032_HCLK_SPI2 132 +#define R9A06G032_HCLK_SPI3 133 +#define R9A06G032_HCLK_SPI4 134 +#define R9A06G032_HCLK_SPI5 135 +#define R9A06G032_HCLK_SWITCH 136 +#define R9A06G032_HCLK_SWITCH_RG 137 +#define R9A06G032_HCLK_UART0 138 +#define R9A06G032_HCLK_UART1 139 +#define R9A06G032_HCLK_UART2 140 +#define R9A06G032_HCLK_UART3 141 +#define R9A06G032_HCLK_UART4 142 +#define R9A06G032_HCLK_UART5 143 +#define R9A06G032_HCLK_UART6 144 +#define R9A06G032_HCLK_UART7 145 +#define R9A06G032_CLK_UART0 146 +#define R9A06G032_CLK_UART1 147 +#define R9A06G032_CLK_UART2 148 +#define R9A06G032_CLK_UART3 149 +#define R9A06G032_CLK_UART4 150 +#define R9A06G032_CLK_UART5 151 +#define R9A06G032_CLK_UART6 152 +#define R9A06G032_CLK_UART7 153 + +#endif /* __DT_BINDINGS_R9A06G032_SYSCTRL_H__ */ From e4b08e1f3e86a5acda93fc7adb014840af7248bb Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Thu, 14 Jun 2018 11:56:31 +0100 Subject: [PATCH 07/85] dt-bindings: clock: renesas,r9a06g032-sysctrl: documentation The Renesas R9A06G032 SYSCTRL node description. Signed-off-by: Michel Pollet Reviewed-by: Rob Herring Signed-off-by: Geert Uytterhoeven --- .../clock/renesas,r9a06g032-sysctrl.txt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt diff --git a/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt new file mode 100644 index 000000000000..d60b99756bb9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt @@ -0,0 +1,43 @@ +* Renesas R9A06G032 SYSCTRL + +Required Properties: + + - compatible: Must be: + - "renesas,r9a06g032-sysctrl" + - reg: Base address and length of the SYSCTRL IO block. + - #clock-cells: Must be 1 + - clocks: References to the parent clocks: + - external 40mhz crystal. + - external (optional) 32.768khz + - external (optional) jtag input + - external (optional) RGMII_REFCLK + - clock-names: Must be: + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + +Examples +-------- + + - SYSCTRL node: + + sysctrl: system-controller@4000c000 { + compatible = "renesas,r9a06g032-sysctrl"; + reg = <0x4000c000 0x1000>; + #clock-cells = <1>; + + clocks = <&ext_mclk>, <&ext_rtc_clk>, + <&ext_jtag_clk>, <&ext_rgmii_ref>; + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + }; + + - Other nodes can use the clocks provided by SYSCTRL as in: + + #include + uart0: serial@40060000 { + compatible = "snps,dw-apb-uart"; + reg = <0x40060000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&sysctrl R9A06G032_CLK_UART0>; + clock-names = "baudclk"; + }; From 4c3d88526eba214357150764a0e3e5308acbef4a Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Thu, 14 Jun 2018 11:56:34 +0100 Subject: [PATCH 08/85] clk: renesas: Renesas R9A06G032 clock driver This provides a clock driver for the Renesas R09A06G032. This uses a structure derived from both the R-Car Gen2 driver as well as the renesas-cpg-mssr driver. Signed-off-by: Michel Pollet Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 6 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r9a06g032-clocks.c | 893 +++++++++++++++++++++++++ 3 files changed, 900 insertions(+) create mode 100644 drivers/clk/renesas/r9a06g032-clocks.c diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index f9ba71311727..9022bbe1297e 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -21,6 +21,7 @@ config CLK_RENESAS select CLK_R8A77980 if ARCH_R8A77980 select CLK_R8A77990 if ARCH_R8A77990 select CLK_R8A77995 if ARCH_R8A77995 + select CLK_R9A06G032 if ARCH_R9A06G032 select CLK_SH73A0 if ARCH_SH73A0 if CLK_RENESAS @@ -125,6 +126,11 @@ config CLK_R8A77995 bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R9A06G032 + bool "Renesas R9A06G032 clock driver" + help + This is a driver for R9A06G032 clocks + config CLK_SH73A0 bool "SH-Mobile AG5 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index fe5bac9215e5..e4aa3d6143d2 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o +obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c new file mode 100644 index 000000000000..a0b6ecdc63dd --- /dev/null +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -0,0 +1,893 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R9A09G032 clock driver + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet , + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct r9a06g032_gate { + u16 gate, reset, ready, midle, + scon, mirack, mistat; +}; + +/* This is used to describe a clock for instantiation */ +struct r9a06g032_clkdesc { + const char *name; + uint32_t type: 3; + uint32_t index: 8; + uint32_t source : 8; /* source index + 1 (0 == none) */ + /* these are used to populate the bitsel struct */ + union { + struct r9a06g032_gate gate; + /* for dividers */ + struct { + unsigned int div_min : 10, div_max : 10, reg: 10; + u16 div_table[4]; + }; + /* For fixed-factor ones */ + struct { + u16 div, mul; + }; + unsigned int factor; + unsigned int frequency; + /* for dual gate */ + struct { + uint16_t group : 1, index: 3; + u16 sel, g1, r1, g2, r2; + } dual; + }; +} __packed; + +#define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \ + { .gate = _clk, .reset = _rst, \ + .ready = _rdy, .midle = _midle, \ + .scon = _scon, .mirack = _mirack, .mistat = _mistat } +#define D_GATE(_idx, _n, _src, ...) \ + { .type = K_GATE, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .gate = I_GATE(__VA_ARGS__), } +#define D_ROOT(_idx, _n, _mul, _div) \ + { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \ + .div = _div, .mul = _mul } +#define D_FFC(_idx, _n, _src, _div) \ + { .type = K_FFC, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .div = _div, .mul = 1} +#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) \ + { .type = K_DIV, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .reg = _reg, .div_min = _min, .div_max = _max, \ + .div_table = { __VA_ARGS__ } } +#define D_UGATE(_idx, _n, _src, _g, _gi, _g1, _r1, _g2, _r2) \ + { .type = K_DUALGATE, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .dual = { .group = _g, .index = _gi, \ + .g1 = _g1, .r1 = _r1, .g2 = _g2, .r2 = _r2 }, } + +enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE }; + +/* Internal clock IDs */ +#define R9A06G032_CLKOUT 0 +#define R9A06G032_CLKOUT_D10 2 +#define R9A06G032_CLKOUT_D16 3 +#define R9A06G032_CLKOUT_D160 4 +#define R9A06G032_CLKOUT_D1OR2 5 +#define R9A06G032_CLKOUT_D20 6 +#define R9A06G032_CLKOUT_D40 7 +#define R9A06G032_CLKOUT_D5 8 +#define R9A06G032_CLKOUT_D8 9 +#define R9A06G032_DIV_ADC 10 +#define R9A06G032_DIV_I2C 11 +#define R9A06G032_DIV_NAND 12 +#define R9A06G032_DIV_P1_PG 13 +#define R9A06G032_DIV_P2_PG 14 +#define R9A06G032_DIV_P3_PG 15 +#define R9A06G032_DIV_P4_PG 16 +#define R9A06G032_DIV_P5_PG 17 +#define R9A06G032_DIV_P6_PG 18 +#define R9A06G032_DIV_QSPI0 19 +#define R9A06G032_DIV_QSPI1 20 +#define R9A06G032_DIV_REF_SYNC 21 +#define R9A06G032_DIV_SDIO0 22 +#define R9A06G032_DIV_SDIO1 23 +#define R9A06G032_DIV_SWITCH 24 +#define R9A06G032_DIV_UART 25 +#define R9A06G032_DIV_MOTOR 64 +#define R9A06G032_CLK_DDRPHY_PLLCLK_D4 78 +#define R9A06G032_CLK_ECAT100_D4 79 +#define R9A06G032_CLK_HSR100_D2 80 +#define R9A06G032_CLK_REF_SYNC_D4 81 +#define R9A06G032_CLK_REF_SYNC_D8 82 +#define R9A06G032_CLK_SERCOS100_D2 83 +#define R9A06G032_DIV_CA7 84 + +#define R9A06G032_UART_GROUP_012 154 +#define R9A06G032_UART_GROUP_34567 155 + +#define R9A06G032_CLOCK_COUNT (R9A06G032_UART_GROUP_34567 + 1) + +static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = { + D_ROOT(CLKOUT, "clkout", 25, 1), + D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10), + D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10), + D_FFC(CLKOUT_D16, "clkout_d16", CLKOUT, 16), + D_FFC(CLKOUT_D160, "clkout_d160", CLKOUT, 160), + D_DIV(CLKOUT_D1OR2, "clkout_d1or2", CLKOUT, 0, 1, 2), + D_FFC(CLKOUT_D20, "clkout_d20", CLKOUT, 20), + D_FFC(CLKOUT_D40, "clkout_d40", CLKOUT, 40), + D_FFC(CLKOUT_D5, "clkout_d5", CLKOUT, 5), + D_FFC(CLKOUT_D8, "clkout_d8", CLKOUT, 8), + D_DIV(DIV_ADC, "div_adc", CLKOUT, 77, 50, 250), + D_DIV(DIV_I2C, "div_i2c", CLKOUT, 78, 12, 16), + D_DIV(DIV_NAND, "div_nand", CLKOUT, 82, 12, 32), + D_DIV(DIV_P1_PG, "div_p1_pg", CLKOUT, 68, 12, 200), + D_DIV(DIV_P2_PG, "div_p2_pg", CLKOUT, 62, 12, 128), + D_DIV(DIV_P3_PG, "div_p3_pg", CLKOUT, 64, 8, 128), + D_DIV(DIV_P4_PG, "div_p4_pg", CLKOUT, 66, 8, 128), + D_DIV(DIV_P5_PG, "div_p5_pg", CLKOUT, 71, 10, 40), + D_DIV(DIV_P6_PG, "div_p6_pg", CLKOUT, 18, 12, 64), + D_DIV(DIV_QSPI0, "div_qspi0", CLKOUT, 73, 3, 7), + D_DIV(DIV_QSPI1, "div_qspi1", CLKOUT, 25, 3, 7), + D_DIV(DIV_REF_SYNC, "div_ref_sync", CLKOUT, 56, 2, 16, 2, 4, 8, 16), + D_DIV(DIV_SDIO0, "div_sdio0", CLKOUT, 74, 20, 128), + D_DIV(DIV_SDIO1, "div_sdio1", CLKOUT, 75, 20, 128), + D_DIV(DIV_SWITCH, "div_switch", CLKOUT, 37, 5, 40), + D_DIV(DIV_UART, "div_uart", CLKOUT, 79, 12, 128), + D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, 0x749, 0x74a, 0x74b, 0, 0xae3, 0, 0), + D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, 0x74c, 0x74d, 0x74e, 0, 0xae4, 0, 0), + D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, 0x74f, 0x750, 0x751, 0, 0xae5, 0, 0), + D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, 0x752, 0x753, 0x754, 0, 0xae6, 0, 0), + D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, 0x755, 0x756, 0x757, 0, 0xae7, 0, 0), + D_GATE(CLK_ADC, "clk_adc", DIV_ADC, 0x1ea, 0x1eb, 0, 0, 0, 0, 0), + D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, 0x405, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, 0x483, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, 0x1e6, 0x1e7, 0, 0, 0, 0, 0), + D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, 0x1e8, 0x1e9, 0, 0, 0, 0, 0), + D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, 0x342, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_NAND, "clk_nand", DIV_NAND, 0x284, 0x285, 0, 0, 0, 0, 0), + D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, 0x774, 0x775, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, 0x862, 0x863, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, 0x864, 0x865, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, 0x866, 0x867, 0, 0, 0, 0, 0), + D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, 0x824, 0x825, 0, 0, 0, 0, 0), + D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, 0x826, 0x827, 0, 0, 0, 0, 0), + D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, 0x8a0, 0x8a1, 0x8a2, 0, 0xb60, 0, 0), + D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0), + D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0), + D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0), + D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0), + D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0), + D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, 0x341, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, 0x64, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, 0x644, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, 0x425, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, 0x860, 0x861, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, 0x7e0, 0x7e1, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, 0x7e2, 0x7e3, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, 0x7e4, 0x7e5, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, 0x7e6, 0x7e7, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, 0x820, 0x821, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0), + D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0), + D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8), + D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441), + D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0), + D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461), + D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0), + D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0), + D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0), + D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0), + D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0), + D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103), + D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101), + D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05), + D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0), + D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4), + D_FFC(CLK_ECAT100_D4, "clk_ecat100_d4", CLK_ECAT100, 4), + D_FFC(CLK_HSR100_D2, "clk_hsr100_d2", CLK_HSR100, 2), + D_FFC(CLK_REF_SYNC_D4, "clk_ref_sync_d4", CLK_REF_SYNC, 4), + D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8), + D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2), + D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4), + D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0), + D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0), + D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0), + D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0), + D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0), + D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0), + D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0), + D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640), + D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1), + D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0), + D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, 0x403, 0x404, 0, 0, 0, 0, 0), + D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0), + D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0), + D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0), + D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0), + D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0), + D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0), + D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141), + D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1), + D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2), + D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5), + D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2), + D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2), + D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0), + D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0), + D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0), + D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1), + D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0), + D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0), + D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0), + D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0), + D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182), + D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2), + D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25), + D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0), + D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0), + D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0), + D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0), + D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302), + D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2), + D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0), + D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0), + D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82), + D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662), + D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0), + D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0), + D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0), + D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0), + D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0), + D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0), + D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0), + D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0), + D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0), + D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0), + D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0), + D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0), + D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0), + D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0), + D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0), + D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0), + D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0), + /* + * These are not hardware clocks, but are needed to handle the special + * case where we have a 'selector bit' that doesn't just change the + * parent for a clock, but also the gate it's suposed to use. + */ + { + .index = R9A06G032_UART_GROUP_012, + .name = "uart_group_012", + .type = K_BITSEL, + .source = 1 + R9A06G032_DIV_UART, + /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */ + .dual.sel = ((0xec / 4) << 5) | 24, + .dual.group = 0, + }, + { + .index = R9A06G032_UART_GROUP_34567, + .name = "uart_group_34567", + .type = K_BITSEL, + .source = 1 + R9A06G032_DIV_P2_PG, + /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */ + .dual.sel = ((0x34 / 4) << 5) | 30, + .dual.group = 1, + }, + D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5), + D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, 1, 0x1b6, 0x1b7, 0x1b8, 0x1b9), + D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, 2, 0x1ba, 0x1bb, 0x1bc, 0x1bd), + D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, 0, 0x760, 0x761, 0x762, 0x763), + D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, 1, 0x764, 0x765, 0x766, 0x767), + D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, 2, 0x768, 0x769, 0x76a, 0x76b), + D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, 3, 0x76c, 0x76d, 0x76e, 0x76f), + D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, 4, 0x770, 0x771, 0x772, 0x773), +}; + +struct r9a06g032_priv { + struct clk_onecell_data data; + spinlock_t lock; /* protects concurent access to gates */ + void __iomem *reg; +}; + +/* register/bit pairs are encoded as an uint16_t */ +static void +clk_rdesc_set(struct r9a06g032_priv *clocks, + u16 one, unsigned int on) +{ + u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); + u32 val = readl(reg); + + val = (val & ~(1U << (one & 0x1f))) | ((!!on) << (one & 0x1f)); + writel(val, reg); +} + +static int +clk_rdesc_get(struct r9a06g032_priv *clocks, + uint16_t one) +{ + u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); + u32 val = readl(reg); + + return !!(val & (1U << (one & 0x1f))); +} + +/* + * This implements the R9A09G032 clock gate 'driver'. We cannot use the system's + * clock gate framework as the gates on the R9A09G032 have a special enabling + * sequence, therefore we use this little proxy. + */ +struct r9a06g032_clk_gate { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + + struct r9a06g032_gate gate; +}; + +#define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw) + +static void +r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks, + struct r9a06g032_gate *g, int on) +{ + unsigned long flags; + + WARN_ON(!g->gate); + + spin_lock_irqsave(&clocks->lock, flags); + clk_rdesc_set(clocks, g->gate, on); + /* De-assert reset */ + if (g->reset) + clk_rdesc_set(clocks, g->reset, 1); + spin_unlock_irqrestore(&clocks->lock, flags); + + /* Hardware manual recommends 5us delay after enabling clock & reset */ + udelay(5); + + /* If the peripheral is memory mapped (i.e. an AXI slave), there is an + * associated SLVRDY bit in the System Controller that needs to be set + * so that the FlexWAY bus fabric passes on the read/write requests. + */ + if (g->ready || g->midle) { + spin_lock_irqsave(&clocks->lock, flags); + if (g->ready) + clk_rdesc_set(clocks, g->ready, on); + /* Clear 'Master Idle Request' bit */ + if (g->midle) + clk_rdesc_set(clocks, g->midle, !on); + spin_unlock_irqrestore(&clocks->lock, flags); + } + /* Note: We don't wait for FlexWAY Socket Connection signal */ +} + +static int r9a06g032_clk_gate_enable(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + r9a06g032_clk_gate_set(g->clocks, &g->gate, 1); + return 0; +} + +static void r9a06g032_clk_gate_disable(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + r9a06g032_clk_gate_set(g->clocks, &g->gate, 0); +} + +static int r9a06g032_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + /* if clock is in reset, the gate might be on, and still not 'be' on */ + if (g->gate.reset && !clk_rdesc_get(g->clocks, g->gate.reset)) + return 0; + + return clk_rdesc_get(g->clocks, g->gate.gate); +} + +static const struct clk_ops r9a06g032_clk_gate_ops = { + .enable = r9a06g032_clk_gate_enable, + .disable = r9a06g032_clk_gate_disable, + .is_enabled = r9a06g032_clk_gate_is_enabled, +}; + +static struct clk * +r9a06g032_register_gate(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct clk *clk; + struct r9a06g032_clk_gate *g; + struct clk_init_data init; + + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + + init.name = desc->name; + init.ops = &r9a06g032_clk_gate_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + g->clocks = clocks; + g->index = desc->index; + g->gate = desc->gate; + g->hw.init = &init; + + /* + * important here, some clocks are already in use by the CM3, we + * have to assume they are not Linux's to play with and try to disable + * at the end of the boot! + */ + if (r9a06g032_clk_gate_is_enabled(&g->hw)) { + init.flags |= CLK_IS_CRITICAL; + pr_debug("%s was enabled, making read-only\n", desc->name); + } + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +struct r9a06g032_clk_div { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 reg; + u16 min, max; + u8 table_size; + u16 table[8]; /* we know there are no more than 8 */ +}; + +#define to_r9a06g032_div(_hw) \ + container_of(_hw, struct r9a06g032_clk_div, hw) + +static unsigned long +r9a06g032_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); + u32 div = readl(reg); + + if (div < clk->min) + div = clk->min; + else if (div > clk->max) + div = clk->max; + return DIV_ROUND_UP(parent_rate, div); +} + +/* + * Attempts to find a value that is in range of min,max, + * and if a table of set dividers was specified for this + * register, try to find the fixed divider that is the closest + * to the target frequency + */ +static long +r9a06g032_div_clamp_div(struct r9a06g032_clk_div *clk, + unsigned long rate, unsigned long prate) +{ + /* + 1 to cope with rates that have the remainder dropped */ + u32 div = DIV_ROUND_UP(prate, rate + 1); + int i; + + if (div <= clk->min) + return clk->min; + if (div >= clk->max) + return clk->max; + + for (i = 0; clk->table_size && i < clk->table_size - 1; i++) { + if (div >= clk->table[i] && div <= clk->table[i + 1]) { + unsigned long m = rate - + DIV_ROUND_UP(prate, clk->table[i]); + unsigned long p = + DIV_ROUND_UP(prate, clk->table[i + 1]) - + rate; + /* + * select the divider that generates + * the value closest to the ideal frequency + */ + div = p >= m ? clk->table[i] : clk->table[i + 1]; + return div; + } + } + return div; +} + +static long +r9a06g032_div_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *prate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + u32 div = DIV_ROUND_UP(*prate, rate); + + pr_devel("%s %pC %ld (prate %ld) (wanted div %u)\n", __func__, + hw->clk, rate, *prate, div); + pr_devel(" min %d (%ld) max %d (%ld)\n", + clk->min, DIV_ROUND_UP(*prate, clk->min), + clk->max, DIV_ROUND_UP(*prate, clk->max)); + + div = r9a06g032_div_clamp_div(clk, rate, *prate); + /* + * this is a hack. Currently the serial driver asks for a clock rate + * that is 16 times the baud rate -- and that is wildly outside the + * range of the UART divider, somehow there is no provision for that + * case of 'let the divider as is if outside range'. + * The serial driver *shouldn't* play with these clocks anyway, there's + * several uarts attached to this divider, and changing this impacts + * everyone. + */ + if (clk->index == R9A06G032_DIV_UART) { + pr_devel("%s div uart hack!\n", __func__); + return clk_get_rate(hw->clk); + } + pr_devel("%s %pC %ld / %u = %ld\n", __func__, hw->clk, + *prate, div, DIV_ROUND_UP(*prate, div)); + return DIV_ROUND_UP(*prate, div); +} + +static int +r9a06g032_div_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + /* + 1 to cope with rates that have the remainder dropped */ + u32 div = DIV_ROUND_UP(parent_rate, rate + 1); + u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); + + pr_devel("%s %pC rate %ld parent %ld div %d\n", __func__, hw->clk, + rate, parent_rate, div); + + /* + * Need to write the bit 31 with the divider value to + * latch it. Technically we should wait until it has been + * cleared too. + * TODO: Find whether this callback is sleepable, in case + * the hardware /does/ require some sort of spinloop here. + */ + writel(div | BIT(31), reg); + + return 0; +} + +static const struct clk_ops r9a06g032_clk_div_ops = { + .recalc_rate = r9a06g032_div_recalc_rate, + .round_rate = r9a06g032_div_round_rate, + .set_rate = r9a06g032_div_set_rate, +}; + +static struct clk * +r9a06g032_register_div(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct r9a06g032_clk_div *div; + struct clk *clk; + struct clk_init_data init; + unsigned int i; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return NULL; + + init.name = desc->name; + init.ops = &r9a06g032_clk_div_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + div->clocks = clocks; + div->index = desc->index; + div->reg = desc->reg; + div->hw.init = &init; + div->min = desc->div_min; + div->max = desc->div_max; + /* populate (optional) divider table fixed values */ + for (i = 0; i < ARRAY_SIZE(div->table) && + i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) { + div->table[div->table_size++] = desc->div_table[i]; + } + + clk = clk_register(NULL, &div->hw); + if (IS_ERR(clk)) { + kfree(div); + return NULL; + } + return clk; +} + +/* + * This clock provider handles the case of the R9A06G032 where you have + * peripherals that have two potential clock source and two gates, one for + * each of the clock source - the used clock source (for all sub clocks) + * is selected by a single bit. + * That single bit affects all sub-clocks, and therefore needs to change the + * active gate (and turn the others off) and force a recalculation of the rates. + * + * This implements two clock providers, one 'bitselect' that + * handles the switch between both parents, and another 'dualgate' + * that knows which gate to poke at, depending on the parent's bit position. + */ +struct r9a06g032_clk_bitsel { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 selector; /* selector register + bit */ +}; + +#define to_clk_bitselect(_hw) \ + container_of(_hw, struct r9a06g032_clk_bitsel, hw) + +static u8 r9a06g032_clk_mux_get_parent(struct clk_hw *hw) +{ + struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); + + return clk_rdesc_get(set->clocks, set->selector); +} + +static int r9a06g032_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); + + /* a single bit in the register selects one of two parent clocks */ + clk_rdesc_set(set->clocks, set->selector, !!index); + + return 0; +} + +static const struct clk_ops clk_bitselect_ops = { + .get_parent = r9a06g032_clk_mux_get_parent, + .set_parent = r9a06g032_clk_mux_set_parent, +}; + +static struct clk * +r9a06g032_register_bitsel(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct clk *clk; + struct r9a06g032_clk_bitsel *g; + struct clk_init_data init; + const char *names[2]; + + /* allocate the gate */ + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + + names[0] = parent_name; + names[1] = "clk_pll_usb"; + + init.name = desc->name; + init.ops = &clk_bitselect_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = names; + init.num_parents = 2; + + g->clocks = clocks; + g->index = desc->index; + g->selector = desc->dual.sel; + g->hw.init = &init; + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +struct r9a06g032_clk_dualgate { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 selector; /* selector register + bit */ + struct r9a06g032_gate gate[2]; +}; + +#define to_clk_dualgate(_hw) \ + container_of(_hw, struct r9a06g032_clk_dualgate, hw) + +static int +r9a06g032_clk_dualgate_setenable(struct r9a06g032_clk_dualgate *g, int enable) +{ + u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); + + /* we always turn off the 'other' gate, regardless */ + r9a06g032_clk_gate_set(g->clocks, &g->gate[!sel_bit], 0); + r9a06g032_clk_gate_set(g->clocks, &g->gate[sel_bit], enable); + + return 0; +} + +static int r9a06g032_clk_dualgate_enable(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); + + r9a06g032_clk_dualgate_setenable(gate, 1); + + return 0; +} + +static void r9a06g032_clk_dualgate_disable(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); + + r9a06g032_clk_dualgate_setenable(gate, 0); +} + +static int r9a06g032_clk_dualgate_is_enabled(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *g = to_clk_dualgate(hw); + u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); + + return clk_rdesc_get(g->clocks, g->gate[sel_bit].gate); +} + +static const struct clk_ops r9a06g032_clk_dualgate_ops = { + .enable = r9a06g032_clk_dualgate_enable, + .disable = r9a06g032_clk_dualgate_disable, + .is_enabled = r9a06g032_clk_dualgate_is_enabled, +}; + +static struct clk * +r9a06g032_register_dualgate(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc, + uint16_t sel) +{ + struct r9a06g032_clk_dualgate *g; + struct clk *clk; + struct clk_init_data init; + + /* allocate the gate */ + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + g->clocks = clocks; + g->index = desc->index; + g->selector = sel; + g->gate[0].gate = desc->dual.g1; + g->gate[0].reset = desc->dual.r1; + g->gate[1].gate = desc->dual.g2; + g->gate[1].reset = desc->dual.r2; + + init.name = desc->name; + init.ops = &r9a06g032_clk_dualgate_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + g->hw.init = &init; + /* + * important here, some clocks are already in use by the CM3, we + * have to assume they are not Linux's to play with and try to disable + * at the end of the boot! + */ + if (r9a06g032_clk_dualgate_is_enabled(&g->hw)) { + init.flags |= CLK_IS_CRITICAL; + pr_debug("%s was enabled, making read-only\n", desc->name); + } + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +static void r9a06g032_clocks_del_clk_provider(void *data) +{ + of_clk_del_provider(data); +} + +static int __init r9a06g032_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct r9a06g032_priv *clocks; + struct clk **clks; + struct clk *mclk; + unsigned int i; + u16 uart_group_sel[2]; + int error; + + clocks = devm_kzalloc(dev, sizeof(*clocks), GFP_KERNEL); + clks = devm_kcalloc(dev, R9A06G032_CLOCK_COUNT, sizeof(struct clk *), + GFP_KERNEL); + if (!clocks || !clks) + return -ENOMEM; + + spin_lock_init(&clocks->lock); + + clocks->data.clks = clks; + clocks->data.clk_num = R9A06G032_CLOCK_COUNT; + + mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(mclk)) + return PTR_ERR(mclk); + + clocks->reg = of_iomap(np, 0); + if (WARN_ON(!clocks->reg)) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(r9a06g032_clocks); ++i) { + const struct r9a06g032_clkdesc *d = &r9a06g032_clocks[i]; + const char *parent_name = d->source ? + __clk_get_name(clocks->data.clks[d->source - 1]) : + __clk_get_name(mclk); + struct clk *clk = NULL; + + switch (d->type) { + case K_FFC: + clk = clk_register_fixed_factor(NULL, d->name, + parent_name, 0, + d->mul, d->div); + break; + case K_GATE: + clk = r9a06g032_register_gate(clocks, parent_name, d); + break; + case K_DIV: + clk = r9a06g032_register_div(clocks, parent_name, d); + break; + case K_BITSEL: + /* keep that selector register around */ + uart_group_sel[d->dual.group] = d->dual.sel; + clk = r9a06g032_register_bitsel(clocks, parent_name, d); + break; + case K_DUALGATE: + clk = r9a06g032_register_dualgate(clocks, parent_name, + d, + uart_group_sel[d->dual.group]); + break; + } + clocks->data.clks[d->index] = clk; + } + error = of_clk_add_provider(np, of_clk_src_onecell_get, &clocks->data); + if (error) + return error; + + return devm_add_action_or_reset(dev, + r9a06g032_clocks_del_clk_provider, np); +} + +static const struct of_device_id r9a06g032_match[] = { + { .compatible = "renesas,r9a06g032-sysctrl" }, + { } +}; + +static struct platform_driver r9a06g032_clock_driver = { + .driver = { + .name = "renesas,r9a06g032-sysctrl", + .of_match_table = r9a06g032_match, + }, +}; + +static int __init r9a06g032_clocks_init(void) +{ + return platform_driver_probe(&r9a06g032_clock_driver, + r9a06g032_clocks_probe); +} + +subsys_initcall(r9a06g032_clocks_init); From 24a95f7578f517e78367d6fb61aba238497a046b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 25 Jun 2018 14:02:41 +0200 Subject: [PATCH 09/85] clk: sunxi-ng: r40: Add minimal rate for video PLLs According to documentation and experience with other similar SoCs, video PLLs don't work stable if their output frequency is set below 192 MHz. Because of that, set minimal rate to both R40 video PLLs to 192 MHz. Reviewed-by: Chen-Yu Tsai Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 46 +++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 65ba6455feb7..d52af1785644 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -66,17 +66,18 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", CLK_SET_RATE_UNGATE); /* TODO: The result of N/M is required to be in [8, 25] range. */ -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", - "osc24M", 0x0010, - 8, 7, /* N */ - 0, 4, /* M */ - BIT(24), /* frac enable */ - BIT(25), /* frac select */ - 270000000, /* frac rate 0 */ - 297000000, /* frac rate 1 */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0", + "osc24M", 0x0010, + 192000000, /* Minimum rate */ + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); /* TODO: The result of N/M is required to be in [8, 25] range. */ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", @@ -152,17 +153,18 @@ static struct ccu_nk pll_periph1_clk = { }; /* TODO: The result of N/M is required to be in [8, 25] range. */ -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", - "osc24M", 0x030, - 8, 7, /* N */ - 0, 4, /* M */ - BIT(24), /* frac enable */ - BIT(25), /* frac select */ - 270000000, /* frac rate 0 */ - 297000000, /* frac rate 1 */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 192000000, /* Minimum rate */ + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static struct ccu_nkm pll_sata_clk = { .enable = BIT(31), From fb4aa0f64380d94bf10b5da63a6760962d824dbc Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 25 Jun 2018 14:02:42 +0200 Subject: [PATCH 10/85] clk: sunxi-ng: r40: Allow setting parent rate to display related clocks Display related peripherals need precise clocks to operate correctly. Allow DE2, TCONs and HDMI to set parent clock. Reviewed-by: Chen-Yu Tsai Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index d52af1785644..0f388f6944d5 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -656,7 +656,8 @@ static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram", static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, - 0x104, 0, 4, 24, 3, BIT(31), 0); + 0x104, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(mp_clk, "mp", de_parents, 0x108, 0, 4, 24, 3, BIT(31), 0); @@ -668,9 +669,11 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_parents, static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_parents, 0x114, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", tcon_parents, - 0x118, 0, 4, 24, 3, BIT(31), 0); + 0x118, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv1_clk, "tcon-tv1", tcon_parents, - 0x11c, 0, 4, 24, 3, BIT(31), 0); + 0x11c, 0, 4, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" }; @@ -700,7 +703,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" }; static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, - 0x150, 0, 4, 24, 2, BIT(31), 0); + 0x150, 0, 4, 24, 2, BIT(31), + CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0x154, BIT(31), 0); From d18e85349f6a65baa69b8ee397efb93e4ca31909 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 25 Jun 2018 14:02:43 +0200 Subject: [PATCH 11/85] clk: sunxi-ng: r40: Export video PLLs Video PLLs need to be referenced in R40 DT as possible HDMI PHY parent. Export them. Reviewed-by: Rob Herring Reviewed-by: Chen-Yu Tsai Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-r40.h | 8 ++++++-- include/dt-bindings/clock/sun8i-r40-ccu.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.h b/drivers/clk/sunxi-ng/ccu-sun8i-r40.h index 0db8e1e97af8..db2a1243f9ff 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.h +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.h @@ -25,7 +25,9 @@ #define CLK_PLL_AUDIO_2X 4 #define CLK_PLL_AUDIO_4X 5 #define CLK_PLL_AUDIO_8X 6 -#define CLK_PLL_VIDEO0 7 + +/* PLL_VIDEO0 is exported */ + #define CLK_PLL_VIDEO0_2X 8 #define CLK_PLL_VE 9 #define CLK_PLL_DDR0 10 @@ -34,7 +36,9 @@ #define CLK_PLL_PERIPH0_2X 13 #define CLK_PLL_PERIPH1 14 #define CLK_PLL_PERIPH1_2X 15 -#define CLK_PLL_VIDEO1 16 + +/* PLL_VIDEO1 is exported */ + #define CLK_PLL_VIDEO1_2X 17 #define CLK_PLL_SATA 18 #define CLK_PLL_SATA_OUT 19 diff --git a/include/dt-bindings/clock/sun8i-r40-ccu.h b/include/dt-bindings/clock/sun8i-r40-ccu.h index 4fa5f69fc297..f9e15a235626 100644 --- a/include/dt-bindings/clock/sun8i-r40-ccu.h +++ b/include/dt-bindings/clock/sun8i-r40-ccu.h @@ -43,6 +43,10 @@ #ifndef _DT_BINDINGS_CLK_SUN8I_R40_H_ #define _DT_BINDINGS_CLK_SUN8I_R40_H_ +#define CLK_PLL_VIDEO0 7 + +#define CLK_PLL_VIDEO1 16 + #define CLK_CPU 24 #define CLK_BUS_MIPI_DSI 29 From f7486bc38c21b24ca418f0c740dd44db9849078d Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 22 Jun 2018 20:26:09 +0800 Subject: [PATCH 12/85] dt-bindings: add compatible string for the A64 DE2 CCU The Allwinner A64 SoC has a DE2 CCU like the one in the DE2 of Allwinner H5 SoC. Add a compatible string for it. Signed-off-by: Icenowy Zheng Reviewed-by: Rob Herring Acked-by: Stephen Boyd Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/clock/sun8i-de2.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt index f2fa87c4765c..e94582e8b8a9 100644 --- a/Documentation/devicetree/bindings/clock/sun8i-de2.txt +++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt @@ -6,6 +6,7 @@ Required properties : - "allwinner,sun8i-a83t-de2-clk" - "allwinner,sun8i-h3-de2-clk" - "allwinner,sun8i-v3s-de2-clk" + - "allwinner,sun50i-a64-de2-clk" - "allwinner,sun50i-h5-de2-clk" - reg: Must contain the registers base address and length From 0195156340d365540c7dfa239232065826904f59 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 22 Jun 2018 20:45:37 +0800 Subject: [PATCH 13/85] clk: sunxi-ng: add A64 compatible string As claiming Allwinner A64 SRAM C is a prerequisite for all sub-blocks of the A64 DE2, not only the CCU sub-block, a bus driver is then written for enabling the access to the whole DE2 part by claiming the SRAM. In this situation, the A64 compatible string will be just added with no other requirments, as they're processed by the parent bus driver. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 468d1abaf0ee..bae5ee67a797 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -288,17 +288,14 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { .compatible = "allwinner,sun8i-v3s-de2-clk", .data = &sun8i_v3s_de2_clk_desc, }, + { + .compatible = "allwinner,sun50i-a64-de2-clk", + .data = &sun50i_a64_de2_clk_desc, + }, { .compatible = "allwinner,sun50i-h5-de2-clk", .data = &sun50i_a64_de2_clk_desc, }, - /* - * The Allwinner A64 SoC needs some bit to be poke in syscon to make - * DE2 really working. - * So there's currently no A64 compatible here. - * H5 shares the same reset line with A64, so here H5 is using the - * clock description of A64. - */ { } }; From e8f127caf63ad29e2b4cb01894b97730384ad1ab Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Mon, 4 Jun 2018 07:34:39 +0200 Subject: [PATCH 14/85] clk-si514, clk-si544: Implement prepare/unprepare/is_prepared operations This adds prepare/unprepare/is_prepared functionality to the drivers for the SI544 and SI514 chips, allowing the clock output to be disabled when the clock is not in use. Signed-off-by: Mike Looijmans Signed-off-by: Stephen Boyd --- drivers/clk/clk-si514.c | 38 +++++++++++++++++++++++++++++++++++++- drivers/clk/clk-si544.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index 09b6718956bd..153b3a2b5857 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool enable) SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0); } +static int si514_prepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + return si514_enable_output(data, true); +} + +static void si514_unprepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + si514_enable_output(data, false); +} + +static int si514_is_prepared(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI514_REG_CONTROL, &val); + if (err < 0) + return err; + + return !!(val & SI514_CONTROL_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si514_get_muldiv(struct clk_si514 *data, struct clk_si514_muldiv *settings) @@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si514 *data = to_clk_si514(hw); struct clk_si514_muldiv settings; + unsigned int old_oe_state; int err; err = si514_calc_muldiv(&settings, rate); if (err) return err; + err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state); + if (err) + return err; + si514_enable_output(data, false); err = si514_set_muldiv(data, &settings); @@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si514_enable_output(data, true); + if (old_oe_state & SI514_CONTROL_OE) + si514_enable_output(data, true); return err; } static const struct clk_ops si514_clk_ops = { + .prepare = si514_prepare, + .unprepare = si514_unprepare, + .is_prepared = si514_is_prepared, .recalc_rate = si514_recalc_rate, .round_rate = si514_round_rate, .set_rate = si514_set_rate, diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 1e2a3b8f9454..64e607f3232a 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -86,6 +86,33 @@ static int si544_enable_output(struct clk_si544 *data, bool enable) SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0); } +static int si544_prepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + return si544_enable_output(data, true); +} + +static void si544_unprepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + si544_enable_output(data, false); +} + +static int si544_is_prepared(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val); + if (err < 0) + return err; + + return !!(val & SI544_OE_STATE_ODC_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si544_get_muldiv(struct clk_si544 *data, struct clk_si544_muldiv *settings) @@ -273,6 +300,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si544 *data = to_clk_si544(hw); struct clk_si544_muldiv settings; + unsigned int old_oe_state; int err; if (!is_valid_frequency(data, rate)) @@ -282,6 +310,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, if (err) return err; + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &old_oe_state); + if (err) + return err; + si544_enable_output(data, false); /* Allow FCAL for this frequency update */ @@ -303,12 +335,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si544_enable_output(data, true); + if (old_oe_state & SI544_OE_STATE_ODC_OE) + si544_enable_output(data, true); return err; } static const struct clk_ops si544_clk_ops = { + .prepare = si544_prepare, + .unprepare = si544_unprepare, + .is_prepared = si544_is_prepared, .recalc_rate = si544_recalc_rate, .round_rate = si544_round_rate, .set_rate = si544_set_rate, From 54614d1218fdf5ccf87ac1499514755fd9c4a179 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 4 Jun 2018 09:06:43 +0800 Subject: [PATCH 15/85] clk: imx6q: remove clks_init_on array Clock framework will enable those clocks registered with CLK_IS_CRITICAL flag, so no need to have clks_init_on array during clock initialization now. ARM clock is busy divider type which has the CLK_IS_CRITICAL flag set by default when registered. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6q.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index b9ea7037e193..8754c6197ef6 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -96,12 +96,6 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; static struct clk *clk[IMX6QDL_CLK_END]; static struct clk_onecell_data clk_data; -static unsigned int const clks_init_on[] __initconst = { - IMX6QDL_CLK_MMDC_CH0_AXI, - IMX6QDL_CLK_ROM, - IMX6QDL_CLK_ARM, -}; - static struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -417,7 +411,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *anatop_base, *base; - int i; int ret; clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -794,7 +787,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "mlb_podf", base + 0x74, 18); else clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); - clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); + clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL); clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); @@ -808,7 +801,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); - clk[IMX6QDL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clk[IMX6QDL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4); clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); @@ -878,9 +871,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) */ clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]); - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clk[clks_init_on[i]]); - if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]); clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]); From 8e12ce99541bdf5ec7cee08683bf455d8c882e49 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 4 Jun 2018 09:06:44 +0800 Subject: [PATCH 16/85] clk: imx6sl: remove clks_init_on array Clock framework will enable those clocks registered with CLK_IS_CRITICAL flag, so no need to have clks_init_on array during clock initialization now. ARM clock is busy divider type which has the CLK_IS_CRITICAL flag set by default when registered. IPG clock has no clock gate and its parent AHB clock is busy divider type, so no need to add CLK_IS_CRITICAL flag for IPG clock. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sl.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c index 66b1dd1cfad0..eb6bcbf345a3 100644 --- a/drivers/clk/imx/clk-imx6sl.c +++ b/drivers/clk/imx/clk-imx6sl.c @@ -104,10 +104,6 @@ static struct clk_onecell_data clk_data; static void __iomem *ccm_base; static void __iomem *anatop_base; -static const u32 clks_init_on[] __initconst = { - IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT, -}; - /* * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken * during WAIT mode entry process could cause cache memory @@ -195,7 +191,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; int ret; clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -426,13 +421,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) pr_warn("%s: failed to set AHB clock rate %d!\n", __func__, ret); - /* - * Make sure those always on clocks are enabled to maintain the correct - * usecount and enabling/disabling of parent PLLs. - */ - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); From 566f5b67fc0c3bffec03a963334eb7c1df30204d Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 4 Jun 2018 09:06:45 +0800 Subject: [PATCH 17/85] clk: imx6sx: remove clks_init_on array Clock framework will enable those clocks registered with CLK_IS_CRITICAL flag, so no need to have clks_init_on array during clock initialization now. ARM clock is busy divider type which has the CLK_IS_CRITICAL flag set by default when registered. IPG clock has no clock gate and its parent AHB clock is busy divider type, so no need to add CLK_IS_CRITICAL flag for IPG clock. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sx.c | 40 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 10c771b91ef6..aed43910e26e 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -92,14 +92,6 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; static struct clk *clks[IMX6SX_CLK_CLK_END]; static struct clk_onecell_data clk_data; -static int const clks_init_on[] __initconst = { - IMX6SX_CLK_AIPS_TZ1, IMX6SX_CLK_AIPS_TZ2, IMX6SX_CLK_AIPS_TZ3, - IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3, - IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG, - IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM, - IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_TZASC1, -}; - static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -142,7 +134,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clks[IMX6SX_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -332,7 +323,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3); - clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); + clks[IMX6SX_CLK_PERCLK] = imx_clk_divider_flags("perclk", "perclk_sel", base + 0x1c, 0, 6, CLK_IS_CRITICAL); clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2); clks[IMX6SX_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6); clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); @@ -380,8 +371,8 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) /* name parent_name reg shift */ /* CCGR0 */ - clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL); clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); clks[IMX6SX_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); clks[IMX6SX_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); @@ -394,7 +385,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20); clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24); clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26); - clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2_flags("aips_tz3", "ahb", base + 0x68, 30, CLK_IS_CRITICAL); /* CCGR1 */ clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -407,7 +398,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x6c, 16, &share_count_esai); clks[IMX6SX_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x6c, 16, &share_count_esai); clks[IMX6SX_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai); - clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18); + clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2_flags("wakeup", "ipg", base + 0x6c, 18, CLK_IS_CRITICAL); clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20); clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); @@ -420,10 +411,10 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14); - clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16); - clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18); - clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20); - clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22); + clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2_flags("ipmux1", "ahb", base + 0x70, 16, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2_flags("ipmux2", "ahb", base + 0x70, 18, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2_flags("ipmux3", "ahb", base + 0x70, 20, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2_flags("tzasc1", "mmdc_podf", base + 0x70, 22, CLK_IS_CRITICAL); clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28); clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30); @@ -437,15 +428,15 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18); - clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); + clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0); clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10); clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12); - clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14); + clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2_flags("per2_main", "ahb", base + 0x78, 14, CLK_IS_CRITICAL); clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); @@ -456,7 +447,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); /* CCGR5 */ - clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6SX_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); clks[IMX6SX_CLK_AUDIO] = imx_clk_gate2_shared("audio", "audio_podf", base + 0x7c, 14, &share_count_audio); @@ -502,9 +493,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clk_data.clk_num = ARRAY_SIZE(clks); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]); clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]); From debef195bd5c79210d60f1d6dec38bde3dae2b88 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Sun, 3 Jun 2018 09:44:04 +0800 Subject: [PATCH 18/85] clk: imx6ul: add GPIO clock gates i.MX6UL has GPIO clock gates in CCM CCGR, add them into clock tree for clock management. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6ul.c | 5 +++++ include/dt-bindings/clock/imx6ul-clock.h | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index ba563ba50b40..3ea2d97562fd 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -360,6 +360,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); if (clk_on_imx6ull()) clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18); + clks[IMX6UL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30); /* CCGR1 */ clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -376,6 +377,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24); + clks[IMX6UL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); + clks[IMX6UL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); /* CCGR2 */ if (clk_on_imx6ull()) { @@ -389,6 +392,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); + clks[IMX6UL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26); clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); @@ -405,6 +409,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); diff --git a/include/dt-bindings/clock/imx6ul-clock.h b/include/dt-bindings/clock/imx6ul-clock.h index 0aa1d9c3e0b9..f8e0476a3a0e 100644 --- a/include/dt-bindings/clock/imx6ul-clock.h +++ b/include/dt-bindings/clock/imx6ul-clock.h @@ -254,6 +254,12 @@ #define IMX6UL_CLK_CKO2_PODF 241 #define IMX6UL_CLK_CKO2 242 #define IMX6UL_CLK_CKO 243 -#define IMX6UL_CLK_END 244 +#define IMX6UL_CLK_GPIO1 244 +#define IMX6UL_CLK_GPIO2 245 +#define IMX6UL_CLK_GPIO3 246 +#define IMX6UL_CLK_GPIO4 247 +#define IMX6UL_CLK_GPIO5 248 + +#define IMX6UL_CLK_END 249 #endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */ From 4a2eaa8e2567297d4dc6e2709841a874927c83aa Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 4 Jun 2018 09:06:46 +0800 Subject: [PATCH 19/85] clk: imx6ul: remove clks_init_on array Clock framework will enable those clocks registered with CLK_IS_CRITICAL flag, so no need to have clks_init_on array during clock initialization now. ARM clock is busy divider type which has the CLK_IS_CRITICAL flag set by default when registered. Signed-off-by: Anson Huang Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6ul.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 3ea2d97562fd..d3f7f4db80af 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -79,12 +79,6 @@ static const char *cko_sels[] = { "cko1", "cko2", }; static struct clk *clks[IMX6UL_CLK_END]; static struct clk_onecell_data clk_data; -static int const clks_init_on[] __initconst = { - IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, - IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, - IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, -}; - static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -129,7 +123,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -336,8 +329,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); /* CCGR0 */ - clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL); clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); @@ -412,9 +405,9 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); - clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); + clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); @@ -428,7 +421,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); /* CCGR5 */ - clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6UL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8); clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); @@ -502,10 +495,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); - /* keep all the clks on just for bringup */ - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - if (clk_on_imx6ull()) clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]); From a7047564fef3ddf0092e64a229ddb17596717120 Mon Sep 17 00:00:00 2001 From: Philipp Puschmann Date: Fri, 8 Jun 2018 12:19:24 +0200 Subject: [PATCH 20/85] clk: imx6: fix video_27m parent for IMX6QDL_CLK_CKO1_SEL q/dl datasheets list the 5th selection value for ck01_sel as video_27M_clk_root. By replacing the dummy value we then can set IMX6QDL_CLK_VIDEO_27M as parent for IMX6QDL_CLK_CKO1_SEL. Signed-off-by: Philipp Puschmann Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index b9ea7037e193..0662db5d37c6 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -65,7 +65,7 @@ static const char *ipg_per_sels[] = { "ipg", "osc", }; static const char *ecspi_sels[] = { "pll3_60m", "osc", }; static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", }; static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", - "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", + "video_27m", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", }; static const char *cko2_sels[] = { "mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1", From 6c0ad1df179b8d26ecd5e9954c36146fa87c1b0c Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Mon, 2 Jul 2018 21:31:17 +0000 Subject: [PATCH 21/85] clk: meson-axg: add pcie and mipi clock bindings Add the pcie and mipi clock dt-bindings for the pcie driver. Since the mipi clock isalso used by the pcie driver, we add it together in this patch. Tested-by: Jianxin Qin Signed-off-by: Yixun Lan Signed-off-by: Jerome Brunet --- include/dt-bindings/clock/axg-clkc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h index 555937a25504..70371228b7e0 100644 --- a/include/dt-bindings/clock/axg-clkc.h +++ b/include/dt-bindings/clock/axg-clkc.h @@ -68,5 +68,8 @@ #define CLKID_SD_EMMC_B_CLK0 59 #define CLKID_SD_EMMC_C_CLK0 60 #define CLKID_HIFI_PLL 69 +#define CLKID_PCIE_CML_EN0 79 +#define CLKID_PCIE_CML_EN1 80 +#define CLKID_MIPI_ENABLE 81 #endif /* __AXG_CLKC_H */ From cfb8282e18e292a8efc4d13ea1e4547a47dfb2d0 Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Mon, 11 Jun 2018 12:08:15 +0530 Subject: [PATCH 22/85] clk: qcom: Enable clocks which needs to be always on for SDM845 There are certain clocks which needs to be always enabled for system operation. Add support for the same by adding 'CLK_IS_CRITICAL' flag for such clocks. Signed-off-by: Amit Nischal Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sdm845.c | 43 +++++++++++++++++++-- include/dt-bindings/clock/qcom,gcc-sdm845.h | 2 + 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index e78e6f5b99fc..0f694ed4238a 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -1103,6 +1103,7 @@ static struct clk_branch gcc_camera_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1129,6 +1130,7 @@ static struct clk_branch gcc_camera_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1270,6 +1272,7 @@ static struct clk_branch gcc_disp_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1328,6 +1331,7 @@ static struct clk_branch gcc_disp_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1397,6 +1401,7 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_cfg_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2985,6 +2990,7 @@ static struct clk_branch gcc_video_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3011,6 +3017,7 @@ static struct clk_branch gcc_video_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3049,6 +3056,36 @@ static struct clk_branch gcc_vs_ctrl_clk = { }, }; +static struct clk_branch gcc_cpuss_dvm_bus_clk = { + .halt_reg = 0x48190, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x48190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_dvm_bus_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_gnoc_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_gnoc_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3344,6 +3381,8 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, [GPLL4] = &gpll4.clkr, + [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, + [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { @@ -3433,10 +3472,6 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); regmap_update_bits(regmap, 0x71028, 0x3, 0x3); - /* Enable CPUSS clocks */ - regmap_update_bits(regmap, 0x48190, BIT(0), 0x1); - regmap_update_bits(regmap, 0x52004, BIT(22), 0x1); - return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); } diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index aca61264f12c..f96fc2dbf60e 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -192,6 +192,8 @@ #define GCC_VS_CTRL_CLK_SRC 182 #define GCC_VSENSOR_CLK_SRC 183 #define GPLL4 184 +#define GCC_CPUSS_DVM_BUS_CLK 185 +#define GCC_CPUSS_GNOC_CLK 186 /* GCC Resets */ #define GCC_MMSS_BCR 0 From 63b8add24e1a99d7218c904f258623e7c07ce99e Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Fri, 15 Jun 2018 10:16:49 +0800 Subject: [PATCH 23/85] clk: rockchip: add dt-binding header for px30 Add the dt-bindings header for the px30, that gets shared between the clock controller and the clock references in the dts. Add softreset ID for px30. Signed-off-by: Elaine Zhang Reviewed-by: Rob Herring Signed-off-by: Heiko Stuebner --- include/dt-bindings/clock/px30-cru.h | 389 +++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 include/dt-bindings/clock/px30-cru.h diff --git a/include/dt-bindings/clock/px30-cru.h b/include/dt-bindings/clock/px30-cru.h new file mode 100644 index 000000000000..00101479f7c4 --- /dev/null +++ b/include/dt-bindings/clock/px30-cru.h @@ -0,0 +1,389 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DT_BINDINGS_CLK_ROCKCHIP_PX30_H +#define _DT_BINDINGS_CLK_ROCKCHIP_PX30_H + +/* core clocks */ +#define PLL_APLL 1 +#define PLL_DPLL 2 +#define PLL_CPLL 3 +#define PLL_NPLL 4 +#define APLL_BOOST_H 5 +#define APLL_BOOST_L 6 +#define ARMCLK 7 + +/* sclk gates (special clocks) */ +#define USB480M 14 +#define SCLK_PDM 15 +#define SCLK_I2S0_TX 16 +#define SCLK_I2S0_TX_OUT 17 +#define SCLK_I2S0_RX 18 +#define SCLK_I2S0_RX_OUT 19 +#define SCLK_I2S1 20 +#define SCLK_I2S1_OUT 21 +#define SCLK_I2S2 22 +#define SCLK_I2S2_OUT 23 +#define SCLK_UART1 24 +#define SCLK_UART2 25 +#define SCLK_UART3 26 +#define SCLK_UART4 27 +#define SCLK_UART5 28 +#define SCLK_I2C0 29 +#define SCLK_I2C1 30 +#define SCLK_I2C2 31 +#define SCLK_I2C3 32 +#define SCLK_I2C4 33 +#define SCLK_PWM0 34 +#define SCLK_PWM1 35 +#define SCLK_SPI0 36 +#define SCLK_SPI1 37 +#define SCLK_TIMER0 38 +#define SCLK_TIMER1 39 +#define SCLK_TIMER2 40 +#define SCLK_TIMER3 41 +#define SCLK_TIMER4 42 +#define SCLK_TIMER5 43 +#define SCLK_TSADC 44 +#define SCLK_SARADC 45 +#define SCLK_OTP 46 +#define SCLK_OTP_USR 47 +#define SCLK_CRYPTO 48 +#define SCLK_CRYPTO_APK 49 +#define SCLK_DDRC 50 +#define SCLK_ISP 51 +#define SCLK_CIF_OUT 52 +#define SCLK_RGA_CORE 53 +#define SCLK_VOPB_PWM 54 +#define SCLK_NANDC 55 +#define SCLK_SDIO 56 +#define SCLK_EMMC 57 +#define SCLK_SFC 58 +#define SCLK_SDMMC 59 +#define SCLK_OTG_ADP 60 +#define SCLK_GMAC_SRC 61 +#define SCLK_GMAC 62 +#define SCLK_GMAC_RX_TX 63 +#define SCLK_MAC_REF 64 +#define SCLK_MAC_REFOUT 65 +#define SCLK_MAC_OUT 66 +#define SCLK_SDMMC_DRV 67 +#define SCLK_SDMMC_SAMPLE 68 +#define SCLK_SDIO_DRV 69 +#define SCLK_SDIO_SAMPLE 70 +#define SCLK_EMMC_DRV 71 +#define SCLK_EMMC_SAMPLE 72 +#define SCLK_GPU 73 +#define SCLK_PVTM 74 +#define SCLK_CORE_VPU 75 +#define SCLK_GMAC_RMII 76 +#define SCLK_UART2_SRC 77 +#define SCLK_NANDC_DIV 78 +#define SCLK_NANDC_DIV50 79 +#define SCLK_SDIO_DIV 80 +#define SCLK_SDIO_DIV50 81 +#define SCLK_EMMC_DIV 82 +#define SCLK_EMMC_DIV50 83 +#define SCLK_DDRCLK 84 +#define SCLK_UART1_SRC 85 + +/* dclk gates */ +#define DCLK_VOPB 150 +#define DCLK_VOPL 151 + +/* aclk gates */ +#define ACLK_GPU 170 +#define ACLK_BUS_PRE 171 +#define ACLK_CRYPTO 172 +#define ACLK_VI_PRE 173 +#define ACLK_VO_PRE 174 +#define ACLK_VPU 175 +#define ACLK_PERI_PRE 176 +#define ACLK_GMAC 178 +#define ACLK_CIF 179 +#define ACLK_ISP 180 +#define ACLK_VOPB 181 +#define ACLK_VOPL 182 +#define ACLK_RGA 183 +#define ACLK_GIC 184 +#define ACLK_DCF 186 +#define ACLK_DMAC 187 +#define ACLK_BUS_SRC 188 +#define ACLK_PERI_SRC 189 + +/* hclk gates */ +#define HCLK_BUS_PRE 240 +#define HCLK_CRYPTO 241 +#define HCLK_VI_PRE 242 +#define HCLK_VO_PRE 243 +#define HCLK_VPU 244 +#define HCLK_PERI_PRE 245 +#define HCLK_MMC_NAND 246 +#define HCLK_SDMMC 247 +#define HCLK_USB 248 +#define HCLK_CIF 249 +#define HCLK_ISP 250 +#define HCLK_VOPB 251 +#define HCLK_VOPL 252 +#define HCLK_RGA 253 +#define HCLK_NANDC 254 +#define HCLK_SDIO 255 +#define HCLK_EMMC 256 +#define HCLK_SFC 257 +#define HCLK_OTG 258 +#define HCLK_HOST 259 +#define HCLK_HOST_ARB 260 +#define HCLK_PDM 261 +#define HCLK_I2S0 262 +#define HCLK_I2S1 263 +#define HCLK_I2S2 264 + +/* pclk gates */ +#define PCLK_BUS_PRE 320 +#define PCLK_DDR 321 +#define PCLK_VO_PRE 322 +#define PCLK_GMAC 323 +#define PCLK_MIPI_DSI 324 +#define PCLK_MIPIDSIPHY 325 +#define PCLK_MIPICSIPHY 326 +#define PCLK_USB_GRF 327 +#define PCLK_DCF 328 +#define PCLK_UART1 329 +#define PCLK_UART2 330 +#define PCLK_UART3 331 +#define PCLK_UART4 332 +#define PCLK_UART5 333 +#define PCLK_I2C0 334 +#define PCLK_I2C1 335 +#define PCLK_I2C2 336 +#define PCLK_I2C3 337 +#define PCLK_I2C4 338 +#define PCLK_PWM0 339 +#define PCLK_PWM1 340 +#define PCLK_SPI0 341 +#define PCLK_SPI1 342 +#define PCLK_SARADC 343 +#define PCLK_TSADC 344 +#define PCLK_TIMER 345 +#define PCLK_OTP_NS 346 +#define PCLK_WDT_NS 347 +#define PCLK_GPIO1 348 +#define PCLK_GPIO2 349 +#define PCLK_GPIO3 350 +#define PCLK_ISP 351 +#define PCLK_CIF 352 +#define PCLK_OTP_PHY 353 + +#define CLK_NR_CLKS (PCLK_OTP_PHY + 1) + +/* pmu-clocks indices */ + +#define PLL_GPLL 1 + +#define SCLK_RTC32K_PMU 4 +#define SCLK_WIFI_PMU 5 +#define SCLK_UART0_PMU 6 +#define SCLK_PVTM_PMU 7 +#define PCLK_PMU_PRE 8 +#define SCLK_REF24M_PMU 9 +#define SCLK_USBPHY_REF 10 +#define SCLK_MIPIDSIPHY_REF 11 + +#define XIN24M_DIV 12 + +#define PCLK_GPIO0_PMU 20 +#define PCLK_UART0_PMU 21 + +#define CLKPMU_NR_CLKS (PCLK_UART0_PMU + 1) + +/* soft-reset indices */ +#define SRST_CORE0_PO 0 +#define SRST_CORE1_PO 1 +#define SRST_CORE2_PO 2 +#define SRST_CORE3_PO 3 +#define SRST_CORE0 4 +#define SRST_CORE1 5 +#define SRST_CORE2 6 +#define SRST_CORE3 7 +#define SRST_CORE0_DBG 8 +#define SRST_CORE1_DBG 9 +#define SRST_CORE2_DBG 10 +#define SRST_CORE3_DBG 11 +#define SRST_TOPDBG 12 +#define SRST_CORE_NOC 13 +#define SRST_STRC_A 14 +#define SRST_L2C 15 + +#define SRST_DAP 16 +#define SRST_CORE_PVTM 17 +#define SRST_GPU 18 +#define SRST_GPU_NIU 19 +#define SRST_UPCTL2 20 +#define SRST_UPCTL2_A 21 +#define SRST_UPCTL2_P 22 +#define SRST_MSCH 23 +#define SRST_MSCH_P 24 +#define SRST_DDRMON_P 25 +#define SRST_DDRSTDBY_P 26 +#define SRST_DDRSTDBY 27 +#define SRST_DDRGRF_p 28 +#define SRST_AXI_SPLIT_A 29 +#define SRST_AXI_CMD_A 30 +#define SRST_AXI_CMD_P 31 + +#define SRST_DDRPHY 32 +#define SRST_DDRPHYDIV 33 +#define SRST_DDRPHY_P 34 +#define SRST_VPU_A 36 +#define SRST_VPU_NIU_A 37 +#define SRST_VPU_H 38 +#define SRST_VPU_NIU_H 39 +#define SRST_VI_NIU_A 40 +#define SRST_VI_NIU_H 41 +#define SRST_ISP_H 42 +#define SRST_ISP 43 +#define SRST_CIF_A 44 +#define SRST_CIF_H 45 +#define SRST_CIF_PCLKIN 46 +#define SRST_MIPICSIPHY_P 47 + +#define SRST_VO_NIU_A 48 +#define SRST_VO_NIU_H 49 +#define SRST_VO_NIU_P 50 +#define SRST_VOPB_A 51 +#define SRST_VOPB_H 52 +#define SRST_VOPB 53 +#define SRST_PWM_VOPB 54 +#define SRST_VOPL_A 55 +#define SRST_VOPL_H 56 +#define SRST_VOPL 57 +#define SRST_RGA_A 58 +#define SRST_RGA_H 59 +#define SRST_RGA 60 +#define SRST_MIPIDSI_HOST_P 61 +#define SRST_MIPIDSIPHY_P 62 +#define SRST_VPU_CORE 63 + +#define SRST_PERI_NIU_A 64 +#define SRST_USB_NIU_H 65 +#define SRST_USB2OTG_H 66 +#define SRST_USB2OTG 67 +#define SRST_USB2OTG_ADP 68 +#define SRST_USB2HOST_H 69 +#define SRST_USB2HOST_ARB_H 70 +#define SRST_USB2HOST_AUX_H 71 +#define SRST_USB2HOST_EHCI 72 +#define SRST_USB2HOST 73 +#define SRST_USBPHYPOR 74 +#define SRST_USBPHY_OTG_PORT 75 +#define SRST_USBPHY_HOST_PORT 76 +#define SRST_USBPHY_GRF 77 +#define SRST_CPU_BOOST_P 78 +#define SRST_CPU_BOOST 79 + +#define SRST_MMC_NAND_NIU_H 80 +#define SRST_SDIO_H 81 +#define SRST_EMMC_H 82 +#define SRST_SFC_H 83 +#define SRST_SFC 84 +#define SRST_SDCARD_NIU_H 85 +#define SRST_SDMMC_H 86 +#define SRST_NANDC_H 89 +#define SRST_NANDC 90 +#define SRST_GMAC_NIU_A 92 +#define SRST_GMAC_NIU_P 93 +#define SRST_GMAC_A 94 + +#define SRST_PMU_NIU_P 96 +#define SRST_PMU_SGRF_P 97 +#define SRST_PMU_GRF_P 98 +#define SRST_PMU 99 +#define SRST_PMU_MEM_P 100 +#define SRST_PMU_GPIO0_P 101 +#define SRST_PMU_UART0_P 102 +#define SRST_PMU_CRU_P 103 +#define SRST_PMU_PVTM 104 +#define SRST_PMU_UART 105 +#define SRST_PMU_NIU_H 106 +#define SRST_PMU_DDR_FAIL_SAVE 107 +#define SRST_PMU_CORE_PERF_A 108 +#define SRST_PMU_CORE_GRF_P 109 +#define SRST_PMU_GPU_PERF_A 110 +#define SRST_PMU_GPU_GRF_P 111 + +#define SRST_CRYPTO_NIU_A 112 +#define SRST_CRYPTO_NIU_H 113 +#define SRST_CRYPTO_A 114 +#define SRST_CRYPTO_H 115 +#define SRST_CRYPTO 116 +#define SRST_CRYPTO_APK 117 +#define SRST_BUS_NIU_H 120 +#define SRST_USB_NIU_P 121 +#define SRST_BUS_TOP_NIU_P 122 +#define SRST_INTMEM_A 123 +#define SRST_GIC_A 124 +#define SRST_ROM_H 126 +#define SRST_DCF_A 127 + +#define SRST_DCF_P 128 +#define SRST_PDM_H 129 +#define SRST_PDM 130 +#define SRST_I2S0_H 131 +#define SRST_I2S0_TX 132 +#define SRST_I2S1_H 133 +#define SRST_I2S1 134 +#define SRST_I2S2_H 135 +#define SRST_I2S2 136 +#define SRST_UART1_P 137 +#define SRST_UART1 138 +#define SRST_UART2_P 139 +#define SRST_UART2 140 +#define SRST_UART3_P 141 +#define SRST_UART3 142 +#define SRST_UART4_P 143 + +#define SRST_UART4 144 +#define SRST_UART5_P 145 +#define SRST_UART5 146 +#define SRST_I2C0_P 147 +#define SRST_I2C0 148 +#define SRST_I2C1_P 149 +#define SRST_I2C1 150 +#define SRST_I2C2_P 151 +#define SRST_I2C2 152 +#define SRST_I2C3_P 153 +#define SRST_I2C3 154 +#define SRST_PWM0_P 157 +#define SRST_PWM0 158 +#define SRST_PWM1_P 159 + +#define SRST_PWM1 160 +#define SRST_SPI0_P 161 +#define SRST_SPI0 162 +#define SRST_SPI1_P 163 +#define SRST_SPI1 164 +#define SRST_SARADC_P 165 +#define SRST_SARADC 166 +#define SRST_TSADC_P 167 +#define SRST_TSADC 168 +#define SRST_TIMER_P 169 +#define SRST_TIMER0 170 +#define SRST_TIMER1 171 +#define SRST_TIMER2 172 +#define SRST_TIMER3 173 +#define SRST_TIMER4 174 +#define SRST_TIMER5 175 + +#define SRST_OTP_NS_P 176 +#define SRST_OTP_NS_SBPI 177 +#define SRST_OTP_NS_USR 178 +#define SRST_OTP_PHY_P 179 +#define SRST_OTP_PHY 180 +#define SRST_WDT_NS_P 181 +#define SRST_GPIO1_P 182 +#define SRST_GPIO2_P 183 +#define SRST_GPIO3_P 184 +#define SRST_SGRF_P 185 +#define SRST_GRF_P 186 +#define SRST_I2S0_RX 191 + +#endif From 97752d2343518169db7e1fb9da7f2386cf2c3727 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Fri, 15 Jun 2018 10:16:48 +0800 Subject: [PATCH 24/85] dt-bindings: add bindings for px30 clock controller Add devicetree bindings for Rockchip cru which found on Rockchip SoCs. Signed-off-by: Elaine Zhang Reviewed-by: Rob Herring Signed-off-by: Heiko Stuebner --- .../bindings/clock/rockchip,px30-cru.txt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/rockchip,px30-cru.txt diff --git a/Documentation/devicetree/bindings/clock/rockchip,px30-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,px30-cru.txt new file mode 100644 index 000000000000..39f0c1ac84ee --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,px30-cru.txt @@ -0,0 +1,65 @@ +* Rockchip PX30 Clock and Reset Unit + +The PX30 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: PMU for CRU should be "rockchip,px30-pmu-cru" +- compatible: CRU should be "rockchip,px30-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing, pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/px30-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "i2sx_clkin" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + +Example: Clock controller node: + + pmucru: clock-controller@ff2bc000 { + compatible = "rockchip,px30-pmucru"; + reg = <0x0 0xff2bc000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@ff2b0000 { + compatible = "rockchip,px30-cru"; + reg = <0x0 0xff2b0000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff030000 { + compatible = "rockchip,px30-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff030000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru SCLK_UART0_PMU>, <&pmucru PCLK_UART0_PMU>; + clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + }; From 956060a52795a060833e8de2d1bb89209e61bed2 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Fri, 15 Jun 2018 10:16:50 +0800 Subject: [PATCH 25/85] clk: rockchip: add support for half divider The new Rockchip socs have optional half divider: The formula is shown as: freq_out = 2*freq_in / (2*div + 3) Is this the same for all of new SoCs. So we use "branch_half_divider" + "COMPOSITE_NOMUX_HALFDIV \ DIV_HALF \ COMPOSITE_HALFDIV \ CMPOSITE_NOGATE_HALFDIV" to hook that special divider clock-type into our clock-tree. Signed-off-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-half-divider.c | 227 ++++++++++++++++++++++++ drivers/clk/rockchip/clk.c | 10 ++ drivers/clk/rockchip/clk.h | 85 +++++++++ 4 files changed, 323 insertions(+) create mode 100644 drivers/clk/rockchip/clk-half-divider.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 98e7b9429b83..4d4b7dee1675 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,6 +6,7 @@ obj-y += clk.o obj-y += clk-pll.o obj-y += clk-cpu.o +obj-y += clk-half-divider.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o obj-y += clk-muxgrf.o diff --git a/drivers/clk/rockchip/clk-half-divider.c b/drivers/clk/rockchip/clk-half-divider.c new file mode 100644 index 000000000000..b8da6e799423 --- /dev/null +++ b/drivers/clk/rockchip/clk-half-divider.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include "clk.h" + +#define div_mask(width) ((1 << (width)) - 1) + +static bool _is_best_half_div(unsigned long rate, unsigned long now, + unsigned long best, unsigned long flags) +{ + if (flags & CLK_DIVIDER_ROUND_CLOSEST) + return abs(rate - now) < abs(rate - best); + + return now <= rate && now > best; +} + +static unsigned long clk_half_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int val; + + val = clk_readl(divider->reg) >> divider->shift; + val &= div_mask(divider->width); + val = val * 2 + 3; + + return DIV_ROUND_UP_ULL(((u64)parent_rate * 2), val); +} + +static int clk_half_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, u8 width, + unsigned long flags) +{ + unsigned int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + unsigned long parent_rate_saved = *best_parent_rate; + + if (!rate) + rate = 1; + + maxdiv = div_mask(width); + + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate); + if (bestdiv < 3) + bestdiv = 0; + else + bestdiv = (bestdiv - 3) / 2; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 0; i <= maxdiv; i++) { + if (((u64)rate * (i * 2 + 3)) == ((u64)parent_rate_saved * 2)) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return i; + } + parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), + ((u64)rate * (i * 2 + 3)) / 2); + now = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), + (i * 2 + 3)); + + if (_is_best_half_div(rate, now, best, flags)) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = div_mask(width); + *best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1); + } + + return bestdiv; +} + +static long clk_half_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int div; + + div = clk_half_divider_bestdiv(hw, rate, prate, + divider->width, + divider->flags); + + return DIV_ROUND_UP_ULL(((u64)*prate * 2), div * 2 + 3); +} + +static int clk_half_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int value; + unsigned long flags = 0; + u32 val; + + value = DIV_ROUND_UP_ULL(((u64)parent_rate * 2), rate); + value = (value - 3) / 2; + value = min_t(unsigned int, value, div_mask(divider->width)); + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = div_mask(divider->width) << (divider->shift + 16); + } else { + val = clk_readl(divider->reg); + val &= ~(div_mask(divider->width) << divider->shift); + } + val |= value << divider->shift; + clk_writel(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + + return 0; +} + +const struct clk_ops clk_half_divider_ops = { + .recalc_rate = clk_half_divider_recalc_rate, + .round_rate = clk_half_divider_round_rate, + .set_rate = clk_half_divider_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_half_divider_ops); + +/** + * Register a clock branch. + * Most clock branches have a form like + * + * src1 --|--\ + * |M |--[GATE]-[DIV]- + * src2 --|--/ + * + * sometimes without one of those components. + */ +struct clk *rockchip_clk_register_halfdiv(const char *name, + const char *const *parent_names, + u8 num_parents, void __iomem *base, + int muxdiv_offset, u8 mux_shift, + u8 mux_width, u8 mux_flags, + u8 div_shift, u8 div_width, + u8 div_flags, int gate_offset, + u8 gate_shift, u8 gate_flags, + unsigned long flags, + spinlock_t *lock) +{ + struct clk *clk; + struct clk_mux *mux = NULL; + struct clk_gate *gate = NULL; + struct clk_divider *div = NULL; + const struct clk_ops *mux_ops = NULL, *div_ops = NULL, + *gate_ops = NULL; + + if (num_parents > 1) { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = base + muxdiv_offset; + mux->shift = mux_shift; + mux->mask = BIT(mux_width) - 1; + mux->flags = mux_flags; + mux->lock = lock; + mux_ops = (mux_flags & CLK_MUX_READ_ONLY) ? &clk_mux_ro_ops + : &clk_mux_ops; + } + + if (gate_offset >= 0) { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto err_gate; + + gate->flags = gate_flags; + gate->reg = base + gate_offset; + gate->bit_idx = gate_shift; + gate->lock = lock; + gate_ops = &clk_gate_ops; + } + + if (div_width > 0) { + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + goto err_div; + + div->flags = div_flags; + div->reg = base + muxdiv_offset; + div->shift = div_shift; + div->width = div_width; + div->lock = lock; + div_ops = &clk_half_divider_ops; + } + + clk = clk_register_composite(NULL, name, parent_names, num_parents, + mux ? &mux->hw : NULL, mux_ops, + div ? &div->hw : NULL, div_ops, + gate ? &gate->hw : NULL, gate_ops, + flags); + + return clk; +err_div: + kfree(gate); +err_gate: + kfree(mux); + return ERR_PTR(-ENOMEM); +} diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 326b3fa44f5d..c3ad92965823 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -492,6 +492,16 @@ void __init rockchip_clk_register_branches( list->gate_flags, flags, list->child, &ctx->lock); break; + case branch_half_divider: + clk = rockchip_clk_register_halfdiv(list->name, + list->parent_names, list->num_parents, + ctx->reg_base, list->muxdiv_offset, + list->mux_shift, list->mux_width, + list->mux_flags, list->div_shift, + list->div_width, list->div_flags, + list->gate_offset, list->gate_shift, + list->gate_flags, flags, &ctx->lock); + break; case branch_gate: flags |= CLK_SET_RATE_PARENT; diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index ef601dded32c..23c569a875d4 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -354,6 +354,7 @@ enum rockchip_clk_branch_type { branch_inverter, branch_factor, branch_ddrclk, + branch_half_divider, }; struct rockchip_clk_branch { @@ -684,6 +685,79 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } +#define COMPOSITE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ + df, go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_half_divider, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define COMPOSITE_NOGATE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, \ + ds, dw, df) \ + { \ + .id = _id, \ + .branch_type = branch_half_divider, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + +#define COMPOSITE_NOMUX_HALFDIV(_id, cname, pname, f, mo, ds, dw, df, \ + go, gs, gf) \ + { \ + .id = _id, \ + .branch_type = branch_half_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = mo, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .gate_offset = go, \ + .gate_shift = gs, \ + .gate_flags = gf, \ + } + +#define DIV_HALF(_id, cname, pname, f, o, s, w, df) \ + { \ + .id = _id, \ + .branch_type = branch_half_divider, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .flags = f, \ + .muxdiv_offset = o, \ + .div_shift = s, \ + .div_width = w, \ + .div_flags = df, \ + .gate_offset = -1, \ + } + struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); void rockchip_clk_of_add_provider(struct device_node *np, @@ -708,6 +782,17 @@ void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx, #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) +struct clk *rockchip_clk_register_halfdiv(const char *name, + const char *const *parent_names, + u8 num_parents, void __iomem *base, + int muxdiv_offset, u8 mux_shift, + u8 mux_width, u8 mux_flags, + u8 div_shift, u8 div_width, + u8 div_flags, int gate_offset, + u8 gate_shift, u8 gate_flags, + unsigned long flags, + spinlock_t *lock); + #ifdef CONFIG_RESET_CONTROLLER void rockchip_register_softrst(struct device_node *np, unsigned int num_regs, From 243229b11121fbc90d9ee875292dfc75ecf53040 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Fri, 15 Jun 2018 10:16:51 +0800 Subject: [PATCH 26/85] clk: rockchip: add clock controller for px30 Add the clock tree definition for the new px30 SoC. Signed-off-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-px30.c | 1039 +++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.h | 41 +- 3 files changed, 1080 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/rockchip/clk-px30.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 4d4b7dee1675..ff35ab463a6f 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -13,6 +13,7 @@ obj-y += clk-muxgrf.o obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o +obj-y += clk-px30.o obj-y += clk-rv1108.o obj-y += clk-rk3036.o obj-y += clk-rk3128.o diff --git a/drivers/clk/rockchip/clk-px30.c b/drivers/clk/rockchip/clk-px30.c new file mode 100644 index 000000000000..601a77f1af78 --- /dev/null +++ b/drivers/clk/rockchip/clk-px30.c @@ -0,0 +1,1039 @@ +/* + * Copyright (c) 2018 Rockchip Electronics Co. Ltd. + * Author: Elaine Zhang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +#define PX30_GRF_SOC_STATUS0 0x480 + +enum px30_plls { + apll, dpll, cpll, npll, apll_b_h, apll_b_l, +}; + +enum px30_pmu_plls { + gpll, +}; + +static struct rockchip_pll_rate_table px30_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0), + RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0), + RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0), + RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0), + RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0), + RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0), + RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0), + RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0), + RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0), + RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0), + RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0), + RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0), + RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), + RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), + RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), + RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), + RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0), + RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0), + RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0), + RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), + RK3036_PLL_RATE(900000000, 4, 300, 2, 1, 1, 0), + RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0), + RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0), + RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0), + RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), + RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0), + RK3036_PLL_RATE(700000000, 6, 350, 2, 1, 1, 0), + RK3036_PLL_RATE(696000000, 1, 58, 2, 1, 1, 0), + RK3036_PLL_RATE(624000000, 1, 52, 2, 1, 1, 0), + RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), + RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), + RK3036_PLL_RATE(504000000, 1, 63, 3, 1, 1, 0), + RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0), + RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE(312000000, 1, 52, 2, 2, 1, 0), + RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE(96000000, 1, 64, 4, 4, 1, 0), + { /* sentinel */ }, +}; + +#define PX30_DIV_ACLKM_MASK 0x7 +#define PX30_DIV_ACLKM_SHIFT 12 +#define PX30_DIV_PCLK_DBG_MASK 0xf +#define PX30_DIV_PCLK_DBG_SHIFT 8 + +#define PX30_CLKSEL0(_aclk_core, _pclk_dbg) \ +{ \ + .reg = PX30_CLKSEL_CON(0), \ + .val = HIWORD_UPDATE(_aclk_core, PX30_DIV_ACLKM_MASK, \ + PX30_DIV_ACLKM_SHIFT) | \ + HIWORD_UPDATE(_pclk_dbg, PX30_DIV_PCLK_DBG_MASK, \ + PX30_DIV_PCLK_DBG_SHIFT), \ +} + +#define PX30_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg) \ +{ \ + .prate = _prate, \ + .divs = { \ + PX30_CLKSEL0(_aclk_core, _pclk_dbg), \ + }, \ +} + +static struct rockchip_cpuclk_rate_table px30_cpuclk_rates[] __initdata = { + PX30_CPUCLK_RATE(1608000000, 1, 7), + PX30_CPUCLK_RATE(1584000000, 1, 7), + PX30_CPUCLK_RATE(1560000000, 1, 7), + PX30_CPUCLK_RATE(1536000000, 1, 7), + PX30_CPUCLK_RATE(1512000000, 1, 7), + PX30_CPUCLK_RATE(1488000000, 1, 5), + PX30_CPUCLK_RATE(1464000000, 1, 5), + PX30_CPUCLK_RATE(1440000000, 1, 5), + PX30_CPUCLK_RATE(1416000000, 1, 5), + PX30_CPUCLK_RATE(1392000000, 1, 5), + PX30_CPUCLK_RATE(1368000000, 1, 5), + PX30_CPUCLK_RATE(1344000000, 1, 5), + PX30_CPUCLK_RATE(1320000000, 1, 5), + PX30_CPUCLK_RATE(1296000000, 1, 5), + PX30_CPUCLK_RATE(1272000000, 1, 5), + PX30_CPUCLK_RATE(1248000000, 1, 5), + PX30_CPUCLK_RATE(1224000000, 1, 5), + PX30_CPUCLK_RATE(1200000000, 1, 5), + PX30_CPUCLK_RATE(1104000000, 1, 5), + PX30_CPUCLK_RATE(1008000000, 1, 5), + PX30_CPUCLK_RATE(912000000, 1, 5), + PX30_CPUCLK_RATE(816000000, 1, 3), + PX30_CPUCLK_RATE(696000000, 1, 3), + PX30_CPUCLK_RATE(600000000, 1, 3), + PX30_CPUCLK_RATE(408000000, 1, 1), + PX30_CPUCLK_RATE(312000000, 1, 1), + PX30_CPUCLK_RATE(216000000, 1, 1), + PX30_CPUCLK_RATE(96000000, 1, 1), +}; + +static const struct rockchip_cpuclk_reg_data px30_cpuclk_data = { + .core_reg = PX30_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0xf, + .mux_core_alt = 1, + .mux_core_main = 0, + .mux_core_shift = 7, + .mux_core_mask = 0x1, +}; + +PNAME(mux_pll_p) = { "xin24m"}; +PNAME(mux_usb480m_p) = { "xin24m", "usb480m_phy", "clk_rtc32k_pmu" }; +PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; +PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +PNAME(mux_ddrstdby_p) = { "clk_ddrphy1x", "clk_stdby_2wrap" }; +PNAME(mux_4plls_p) = { "gpll", "dummy_cpll", "usb480m", "npll" }; +PNAME(mux_cpll_npll_p) = { "cpll", "npll" }; +PNAME(mux_npll_cpll_p) = { "npll", "cpll" }; +PNAME(mux_gpll_cpll_p) = { "gpll", "dummy_cpll" }; +PNAME(mux_gpll_npll_p) = { "gpll", "npll" }; +PNAME(mux_gpll_xin24m_p) = { "gpll", "xin24m"}; +PNAME(mux_gpll_cpll_npll_p) = { "gpll", "dummy_cpll", "npll" }; +PNAME(mux_gpll_cpll_npll_xin24m_p) = { "gpll", "dummy_cpll", "npll", "xin24m" }; +PNAME(mux_gpll_xin24m_npll_p) = { "gpll", "xin24m", "npll"}; +PNAME(mux_pdm_p) = { "clk_pdm_src", "clk_pdm_frac" }; +PNAME(mux_i2s0_tx_p) = { "clk_i2s0_tx_src", "clk_i2s0_tx_frac", "mclk_i2s0_tx_in", "xin12m"}; +PNAME(mux_i2s0_rx_p) = { "clk_i2s0_rx_src", "clk_i2s0_rx_frac", "mclk_i2s0_rx_in", "xin12m"}; +PNAME(mux_i2s1_p) = { "clk_i2s1_src", "clk_i2s1_frac", "i2s1_clkin", "xin12m"}; +PNAME(mux_i2s2_p) = { "clk_i2s2_src", "clk_i2s2_frac", "i2s2_clkin", "xin12m"}; +PNAME(mux_i2s0_tx_out_p) = { "clk_i2s0_tx", "xin12m", "clk_i2s0_rx"}; +PNAME(mux_i2s0_rx_out_p) = { "clk_i2s0_rx", "xin12m", "clk_i2s0_tx"}; +PNAME(mux_i2s1_out_p) = { "clk_i2s1", "xin12m"}; +PNAME(mux_i2s2_out_p) = { "clk_i2s2", "xin12m"}; +PNAME(mux_i2s0_tx_rx_p) = { "clk_i2s0_tx_mux", "clk_i2s0_rx_mux"}; +PNAME(mux_i2s0_rx_tx_p) = { "clk_i2s0_rx_mux", "clk_i2s0_tx_mux"}; +PNAME(mux_uart_src_p) = { "gpll", "xin24m", "usb480m", "npll" }; +PNAME(mux_uart1_p) = { "clk_uart1_src", "clk_uart1_np5", "clk_uart1_frac" }; +PNAME(mux_uart2_p) = { "clk_uart2_src", "clk_uart2_np5", "clk_uart2_frac" }; +PNAME(mux_uart3_p) = { "clk_uart3_src", "clk_uart3_np5", "clk_uart3_frac" }; +PNAME(mux_uart4_p) = { "clk_uart4_src", "clk_uart4_np5", "clk_uart4_frac" }; +PNAME(mux_uart5_p) = { "clk_uart5_src", "clk_uart5_np5", "clk_uart5_frac" }; +PNAME(mux_cif_out_p) = { "xin24m", "dummy_cpll", "npll", "usb480m" }; +PNAME(mux_dclk_vopb_p) = { "dclk_vopb_src", "dclk_vopb_frac", "xin24m" }; +PNAME(mux_dclk_vopl_p) = { "dclk_vopl_src", "dclk_vopl_frac", "xin24m" }; +PNAME(mux_gmac_p) = { "clk_gmac_src", "gmac_clkin" }; +PNAME(mux_gmac_rmii_sel_p) = { "clk_gmac_rx_tx_div20", "clk_gmac_rx_tx_div2" }; +PNAME(mux_rtc32k_pmu_p) = { "xin32k", "pmu_pvtm_32k", "clk_rtc32k_frac", }; +PNAME(mux_wifi_pmu_p) = { "xin24m", "clk_wifi_pmu_src" }; +PNAME(mux_uart0_pmu_p) = { "clk_uart0_pmu_src", "clk_uart0_np5", "clk_uart0_frac" }; +PNAME(mux_usbphy_ref_p) = { "xin24m", "clk_ref24m_pmu" }; +PNAME(mux_mipidsiphy_ref_p) = { "xin24m", "clk_ref24m_pmu" }; +PNAME(mux_gpu_p) = { "clk_gpu_div", "clk_gpu_np5" }; + +static struct rockchip_pll_clock px30_pll_clks[] __initdata = { + [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p, + 0, PX30_PLL_CON(0), + PX30_MODE_CON, 0, 0, 0, px30_pll_rates), + [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p, + 0, PX30_PLL_CON(8), + PX30_MODE_CON, 4, 1, 0, NULL), + [cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p, + 0, PX30_PLL_CON(16), + PX30_MODE_CON, 2, 2, 0, px30_pll_rates), + [npll] = PLL(pll_rk3328, PLL_NPLL, "npll", mux_pll_p, + 0, PX30_PLL_CON(24), + PX30_MODE_CON, 6, 4, 0, px30_pll_rates), +}; + +static struct rockchip_pll_clock px30_pmu_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p, 0, PX30_PMU_PLL_CON(0), + PX30_PMU_MODE, 0, 3, 0, px30_pll_rates), +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) + +static struct rockchip_clk_branch px30_pdm_fracmux __initdata = + MUX(0, "clk_pdm_mux", mux_pdm_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(26), 15, 1, MFLAGS); + +static struct rockchip_clk_branch px30_i2s0_tx_fracmux __initdata = + MUX(0, "clk_i2s0_tx_mux", mux_i2s0_tx_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(28), 10, 2, MFLAGS); + +static struct rockchip_clk_branch px30_i2s0_rx_fracmux __initdata = + MUX(0, "clk_i2s0_rx_mux", mux_i2s0_rx_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(58), 10, 2, MFLAGS); + +static struct rockchip_clk_branch px30_i2s1_fracmux __initdata = + MUX(0, "clk_i2s1_mux", mux_i2s1_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(30), 10, 2, MFLAGS); + +static struct rockchip_clk_branch px30_i2s2_fracmux __initdata = + MUX(0, "clk_i2s2_mux", mux_i2s2_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(32), 10, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart1_fracmux __initdata = + MUX(0, "clk_uart1_mux", mux_uart1_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(35), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart2_fracmux __initdata = + MUX(0, "clk_uart2_mux", mux_uart2_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(38), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart3_fracmux __initdata = + MUX(0, "clk_uart3_mux", mux_uart3_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(41), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart4_fracmux __initdata = + MUX(0, "clk_uart4_mux", mux_uart4_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(44), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart5_fracmux __initdata = + MUX(0, "clk_uart5_mux", mux_uart5_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(47), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_dclk_vopb_fracmux __initdata = + MUX(0, "dclk_vopb_mux", mux_dclk_vopb_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(5), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_dclk_vopl_fracmux __initdata = + MUX(0, "dclk_vopl_mux", mux_dclk_vopl_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(8), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_rtc32k_pmu_fracmux __initdata = + MUX(SCLK_RTC32K_PMU, "clk_rtc32k_pmu", mux_rtc32k_pmu_p, CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(0), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_uart0_pmu_fracmux __initdata = + MUX(0, "clk_uart0_pmu_mux", mux_uart0_pmu_p, CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(4), 14, 2, MFLAGS); + +static struct rockchip_clk_branch px30_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 1 + */ + + MUX(USB480M, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT, + PX30_MODE_CON, 8, 2, MFLAGS), + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + + /* + * Clock-Architecture Diagram 3 + */ + + /* PD_CORE */ + GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 0, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(0), 8, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + PX30_CLKGATE_CON(0), 2, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(0), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, + PX30_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "aclk_core_niu", "aclk_core", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "aclk_core_prf", "aclk_core", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(17), 5, GFLAGS), + GATE(0, "pclk_dbg_niu", "pclk_dbg", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 5, GFLAGS), + GATE(0, "pclk_core_dbg", "pclk_dbg", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "pclk_core_grf", "pclk_dbg", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(17), 6, GFLAGS), + + GATE(0, "clk_jtag", "jtag_clkin", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 3, GFLAGS), + GATE(SCLK_PVTM, "clk_pvtm", "xin24m", 0, + PX30_CLKGATE_CON(17), 4, GFLAGS), + + /* PD_GPU */ + COMPOSITE_NODIV(0, "clk_gpu_src", mux_4plls_p, 0, + PX30_CLKSEL_CON(1), 6, 2, MFLAGS, + PX30_CLKGATE_CON(0), 8, GFLAGS), + COMPOSITE_NOMUX(0, "clk_gpu_div", "clk_gpu_src", 0, + PX30_CLKSEL_CON(1), 0, 4, DFLAGS, + PX30_CLKGATE_CON(0), 12, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_gpu_np5", "clk_gpu_src", 0, + PX30_CLKSEL_CON(1), 8, 4, DFLAGS, + PX30_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_NODIV(SCLK_GPU, "clk_gpu", mux_gpu_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(1), 15, 1, MFLAGS, + PX30_CLKGATE_CON(0), 10, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_gpu", "clk_gpu", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(1), 13, 2, DFLAGS, + PX30_CLKGATE_CON(17), 10, GFLAGS), + GATE(0, "aclk_gpu_niu", "aclk_gpu", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 11, GFLAGS), + GATE(0, "aclk_gpu_prf", "aclk_gpu", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(17), 8, GFLAGS), + GATE(0, "pclk_gpu_grf", "aclk_gpu", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(17), 9, GFLAGS), + + /* + * Clock-Architecture Diagram 4 + */ + + /* PD_DDR */ + GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 7, GFLAGS), + GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 13, GFLAGS), + COMPOSITE_NOGATE(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(2), 7, 1, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + COMPOSITE_NOGATE(0, "clk_ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(2), 7, 1, MFLAGS, 0, 3, DFLAGS), + FACTOR_GATE(0, "clk_ddrphy1x", "clk_ddrphy4x", CLK_IGNORE_UNUSED, 1, 4, + PX30_CLKGATE_CON(0), 14, GFLAGS), + FACTOR_GATE(0, "clk_stdby_2wrap", "clk_ddrphy4x", CLK_IGNORE_UNUSED, 1, 4, + PX30_CLKGATE_CON(1), 0, GFLAGS), + COMPOSITE_NODIV(0, "clk_ddrstdby", mux_ddrstdby_p, CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(2), 4, 1, MFLAGS, + PX30_CLKGATE_CON(1), 13, GFLAGS), + GATE(0, "aclk_split", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 15, GFLAGS), + GATE(0, "clk_msch", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 8, GFLAGS), + GATE(0, "aclk_ddrc", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 5, GFLAGS), + GATE(0, "clk_core_ddrc", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 6, GFLAGS), + GATE(0, "aclk_cmd_buff", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 6, GFLAGS), + GATE(0, "clk_ddrmon", "clk_ddrphy1x", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 11, GFLAGS), + + GATE(0, "clk_ddrmon_timer", "xin24m", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(0), 15, GFLAGS), + + COMPOSITE_NOMUX(PCLK_DDR, "pclk_ddr", "gpll", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(2), 8, 5, DFLAGS, + PX30_CLKGATE_CON(1), 1, GFLAGS), + GATE(0, "pclk_ddrmon", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 10, GFLAGS), + GATE(0, "pclk_ddrc", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 7, GFLAGS), + GATE(0, "pclk_msch", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 9, GFLAGS), + GATE(0, "pclk_stdby", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 12, GFLAGS), + GATE(0, "pclk_ddr_grf", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 14, GFLAGS), + GATE(0, "pclk_cmdbuff", "pclk_ddr", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(1), 3, GFLAGS), + + /* + * Clock-Architecture Diagram 5 + */ + + /* PD_VI */ + COMPOSITE(ACLK_VI_PRE, "aclk_vi_pre", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(11), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(4), 8, GFLAGS), + COMPOSITE_NOMUX(HCLK_VI_PRE, "hclk_vi_pre", "aclk_vi_pre", 0, + PX30_CLKSEL_CON(11), 8, 4, DFLAGS, + PX30_CLKGATE_CON(4), 12, GFLAGS), + COMPOSITE(SCLK_ISP, "clk_isp", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(12), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(4), 9, GFLAGS), + COMPOSITE(SCLK_CIF_OUT, "clk_cif_out", mux_cif_out_p, 0, + PX30_CLKSEL_CON(13), 6, 2, MFLAGS, 0, 6, DFLAGS, + PX30_CLKGATE_CON(4), 11, GFLAGS), + GATE(PCLK_ISP, "pclkin_isp", "ext_pclkin", 0, + PX30_CLKGATE_CON(4), 13, GFLAGS), + GATE(PCLK_CIF, "pclkin_cif", "ext_pclkin", 0, + PX30_CLKGATE_CON(4), 14, GFLAGS), + + /* + * Clock-Architecture Diagram 6 + */ + + /* PD_VO */ + COMPOSITE(ACLK_VO_PRE, "aclk_vo_pre", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(3), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE_NOMUX(HCLK_VO_PRE, "hclk_vo_pre", "aclk_vo_pre", 0, + PX30_CLKSEL_CON(3), 8, 4, DFLAGS, + PX30_CLKGATE_CON(2), 12, GFLAGS), + COMPOSITE_NOMUX(PCLK_VO_PRE, "pclk_vo_pre", "aclk_vo_pre", 0, + PX30_CLKSEL_CON(3), 12, 4, DFLAGS, + PX30_CLKGATE_CON(2), 13, GFLAGS), + COMPOSITE(SCLK_RGA_CORE, "clk_rga_core", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(2), 1, GFLAGS), + + COMPOSITE(SCLK_VOPB_PWM, "clk_vopb_pwm", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(7), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(2), 5, GFLAGS), + COMPOSITE(0, "dclk_vopb_src", mux_cpll_npll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + PX30_CLKSEL_CON(5), 11, 1, MFLAGS, 0, 8, DFLAGS, + PX30_CLKGATE_CON(2), 2, GFLAGS), + COMPOSITE_FRACMUX(0, "dclk_vopb_frac", "dclk_vopb_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(6), 0, + PX30_CLKGATE_CON(2), 3, GFLAGS, + &px30_dclk_vopb_fracmux), + GATE(DCLK_VOPB, "dclk_vopb", "dclk_vopb_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(2), 4, GFLAGS), + COMPOSITE(0, "dclk_vopl_src", mux_npll_cpll_p, 0, + PX30_CLKSEL_CON(8), 11, 1, MFLAGS, 0, 8, DFLAGS, + PX30_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE_FRACMUX(0, "dclk_vopl_frac", "dclk_vopl_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(9), 0, + PX30_CLKGATE_CON(2), 7, GFLAGS, + &px30_dclk_vopl_fracmux), + GATE(DCLK_VOPL, "dclk_vopl", "dclk_vopl_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(2), 8, GFLAGS), + + /* PD_VPU */ + COMPOSITE(0, "aclk_vpu_pre", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(10), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(4), 0, GFLAGS), + COMPOSITE_NOMUX(0, "hclk_vpu_pre", "aclk_vpu_pre", 0, + PX30_CLKSEL_CON(10), 8, 4, DFLAGS, + PX30_CLKGATE_CON(4), 2, GFLAGS), + COMPOSITE(SCLK_CORE_VPU, "sclk_core_vpu", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(13), 14, 2, MFLAGS, 8, 5, DFLAGS, + PX30_CLKGATE_CON(4), 1, GFLAGS), + + /* + * Clock-Architecture Diagram 7 + */ + + COMPOSITE_NODIV(ACLK_PERI_SRC, "aclk_peri_src", mux_gpll_cpll_p, 0, + PX30_CLKSEL_CON(14), 15, 1, MFLAGS, + PX30_CLKGATE_CON(5), 7, GFLAGS), + COMPOSITE_NOMUX(ACLK_PERI_PRE, "aclk_peri_pre", "aclk_peri_src", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(14), 0, 5, DFLAGS, + PX30_CLKGATE_CON(5), 8, GFLAGS), + DIV(HCLK_PERI_PRE, "hclk_peri_pre", "aclk_peri_src", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(14), 8, 5, DFLAGS), + + /* PD_MMC_NAND */ + GATE(HCLK_MMC_NAND, "hclk_mmc_nand", "hclk_peri_pre", 0, + PX30_CLKGATE_CON(6), 0, GFLAGS), + COMPOSITE(SCLK_NANDC, "clk_nandc", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(5), 13, GFLAGS), + + COMPOSITE(SCLK_SDIO, "clk_sdio", mux_gpll_cpll_npll_xin24m_p, 0, + PX30_CLKSEL_CON(18), 14, 2, MFLAGS, 0, 8, DFLAGS, + PX30_CLKGATE_CON(6), 3, GFLAGS), + + COMPOSITE(SCLK_EMMC, "clk_emmc", mux_gpll_cpll_npll_xin24m_p, 0, + PX30_CLKSEL_CON(20), 14, 2, MFLAGS, 0, 8, DFLAGS, + PX30_CLKGATE_CON(6), 6, GFLAGS), + + COMPOSITE(SCLK_SFC, "clk_sfc", mux_gpll_cpll_p, 0, + PX30_CLKSEL_CON(22), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(6), 7, GFLAGS), + + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", + PX30_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", + PX30_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", + PX30_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", + PX30_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc", + PX30_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc", + PX30_EMMC_CON1, 1), + + /* PD_SDCARD */ + GATE(0, "hclk_sdmmc_pre", "hclk_peri_pre", 0, + PX30_CLKGATE_CON(6), 12, GFLAGS), + COMPOSITE(SCLK_SDMMC, "clk_sdmmc", mux_gpll_cpll_npll_xin24m_p, 0, + PX30_CLKSEL_CON(16), 14, 2, MFLAGS, 0, 8, DFLAGS, + PX30_CLKGATE_CON(6), 15, GFLAGS), + + /* PD_USB */ + GATE(HCLK_USB, "hclk_usb", "hclk_peri_pre", 0, + PX30_CLKGATE_CON(7), 2, GFLAGS), + GATE(SCLK_OTG_ADP, "clk_otg_adp", "clk_rtc32k_pmu", 0, + PX30_CLKGATE_CON(7), 3, GFLAGS), + + /* PD_GMAC */ + COMPOSITE(SCLK_GMAC_SRC, "clk_gmac_src", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(22), 14, 2, MFLAGS, 8, 5, DFLAGS, + PX30_CLKGATE_CON(7), 11, GFLAGS), + MUX(SCLK_GMAC, "clk_gmac", mux_gmac_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(23), 6, 1, MFLAGS), + GATE(SCLK_MAC_REF, "clk_mac_ref", "clk_gmac", 0, + PX30_CLKGATE_CON(7), 15, GFLAGS), + GATE(SCLK_GMAC_RX_TX, "clk_gmac_rx_tx", "clk_gmac", 0, + PX30_CLKGATE_CON(7), 13, GFLAGS), + FACTOR(0, "clk_gmac_rx_tx_div2", "clk_gmac_rx_tx", 0, 1, 2), + FACTOR(0, "clk_gmac_rx_tx_div20", "clk_gmac_rx_tx", 0, 1, 20), + MUX(SCLK_GMAC_RMII, "clk_gmac_rmii_sel", mux_gmac_rmii_sel_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(23), 7, 1, MFLAGS), + + GATE(0, "aclk_gmac_pre", "aclk_peri_pre", 0, + PX30_CLKGATE_CON(7), 10, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_gmac_pre", "aclk_gmac_pre", 0, + PX30_CLKSEL_CON(23), 0, 4, DFLAGS, + PX30_CLKGATE_CON(7), 12, GFLAGS), + + COMPOSITE(SCLK_MAC_OUT, "clk_mac_out", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 5, DFLAGS, + PX30_CLKGATE_CON(8), 5, GFLAGS), + + /* + * Clock-Architecture Diagram 8 + */ + + /* PD_BUS */ + COMPOSITE_NODIV(ACLK_BUS_SRC, "aclk_bus_src", mux_gpll_cpll_p, CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(23), 15, 1, MFLAGS, + PX30_CLKGATE_CON(8), 6, GFLAGS), + COMPOSITE_NOMUX(HCLK_BUS_PRE, "hclk_bus_pre", "aclk_bus_src", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(24), 0, 5, DFLAGS, + PX30_CLKGATE_CON(8), 8, GFLAGS), + COMPOSITE_NOMUX(ACLK_BUS_PRE, "aclk_bus_pre", "aclk_bus_src", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(23), 8, 5, DFLAGS, + PX30_CLKGATE_CON(8), 7, GFLAGS), + COMPOSITE_NOMUX(PCLK_BUS_PRE, "pclk_bus_pre", "aclk_bus_pre", CLK_IGNORE_UNUSED, + PX30_CLKSEL_CON(24), 8, 2, DFLAGS, + PX30_CLKGATE_CON(8), 9, GFLAGS), + GATE(0, "pclk_top_pre", "pclk_bus_pre", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(8), 10, GFLAGS), + + COMPOSITE(0, "clk_pdm_src", mux_gpll_xin24m_npll_p, 0, + PX30_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(9), 9, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_pdm_frac", "clk_pdm_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(27), 0, + PX30_CLKGATE_CON(9), 10, GFLAGS, + &px30_pdm_fracmux), + GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(9), 11, GFLAGS), + + COMPOSITE(0, "clk_i2s0_tx_src", mux_gpll_npll_p, 0, + PX30_CLKSEL_CON(28), 8, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(9), 12, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s0_tx_frac", "clk_i2s0_tx_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(29), 0, + PX30_CLKGATE_CON(9), 13, GFLAGS, + &px30_i2s0_tx_fracmux), + COMPOSITE_NODIV(SCLK_I2S0_TX, "clk_i2s0_tx", mux_i2s0_tx_rx_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(28), 12, 1, MFLAGS, + PX30_CLKGATE_CON(9), 14, GFLAGS), + COMPOSITE_NODIV(0, "clk_i2s0_tx_out_pre", mux_i2s0_tx_out_p, 0, + PX30_CLKSEL_CON(28), 14, 2, MFLAGS, + PX30_CLKGATE_CON(9), 15, GFLAGS), + GATE(SCLK_I2S0_TX_OUT, "clk_i2s0_tx_out", "clk_i2s0_tx_out_pre", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 8, CLK_GATE_HIWORD_MASK), + + COMPOSITE(0, "clk_i2s0_rx_src", mux_gpll_npll_p, 0, + PX30_CLKSEL_CON(58), 8, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(17), 0, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s0_rx_frac", "clk_i2s0_rx_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(59), 0, + PX30_CLKGATE_CON(17), 1, GFLAGS, + &px30_i2s0_rx_fracmux), + COMPOSITE_NODIV(SCLK_I2S0_RX, "clk_i2s0_rx", mux_i2s0_rx_tx_p, CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(58), 12, 1, MFLAGS, + PX30_CLKGATE_CON(17), 2, GFLAGS), + COMPOSITE_NODIV(0, "clk_i2s0_rx_out_pre", mux_i2s0_rx_out_p, 0, + PX30_CLKSEL_CON(58), 14, 2, MFLAGS, + PX30_CLKGATE_CON(17), 3, GFLAGS), + GATE(SCLK_I2S0_RX_OUT, "clk_i2s0_rx_out", "clk_i2s0_rx_out_pre", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 11, CLK_GATE_HIWORD_MASK), + + COMPOSITE(0, "clk_i2s1_src", mux_gpll_npll_p, 0, + PX30_CLKSEL_CON(30), 8, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(10), 0, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(31), 0, + PX30_CLKGATE_CON(10), 1, GFLAGS, + &px30_i2s1_fracmux), + GATE(SCLK_I2S1, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 2, GFLAGS), + COMPOSITE_NODIV(0, "clk_i2s1_out_pre", mux_i2s1_out_p, 0, + PX30_CLKSEL_CON(30), 15, 1, MFLAGS, + PX30_CLKGATE_CON(10), 3, GFLAGS), + GATE(SCLK_I2S1_OUT, "clk_i2s1_out", "clk_i2s1_out_pre", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 9, CLK_GATE_HIWORD_MASK), + + COMPOSITE(0, "clk_i2s2_src", mux_gpll_npll_p, 0, + PX30_CLKSEL_CON(32), 8, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(10), 4, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(33), 0, + PX30_CLKGATE_CON(10), 5, GFLAGS, + &px30_i2s2_fracmux), + GATE(SCLK_I2S2, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 6, GFLAGS), + COMPOSITE_NODIV(0, "clk_i2s2_out_pre", mux_i2s2_out_p, 0, + PX30_CLKSEL_CON(32), 15, 1, MFLAGS, + PX30_CLKGATE_CON(10), 7, GFLAGS), + GATE(SCLK_I2S2_OUT, "clk_i2s2_out", "clk_i2s2_out_pre", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 10, CLK_GATE_HIWORD_MASK), + + COMPOSITE(SCLK_UART1_SRC, "clk_uart1_src", mux_uart_src_p, CLK_SET_RATE_NO_REPARENT, + PX30_CLKSEL_CON(34), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(10), 12, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart1_np5", "clk_uart1_src", 0, + PX30_CLKSEL_CON(35), 0, 5, DFLAGS, + PX30_CLKGATE_CON(10), 13, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(36), 0, + PX30_CLKGATE_CON(10), 14, GFLAGS, + &px30_uart1_fracmux), + GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(10), 15, GFLAGS), + + COMPOSITE(SCLK_UART2_SRC, "clk_uart2_src", mux_uart_src_p, 0, + PX30_CLKSEL_CON(37), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 0, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart2_np5", "clk_uart2_src", 0, + PX30_CLKSEL_CON(38), 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 1, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(39), 0, + PX30_CLKGATE_CON(11), 2, GFLAGS, + &px30_uart2_fracmux), + GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(11), 3, GFLAGS), + + COMPOSITE(0, "clk_uart3_src", mux_uart_src_p, 0, + PX30_CLKSEL_CON(40), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 4, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart3_np5", "clk_uart3_src", 0, + PX30_CLKSEL_CON(41), 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 5, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(42), 0, + PX30_CLKGATE_CON(11), 6, GFLAGS, + &px30_uart3_fracmux), + GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(11), 7, GFLAGS), + + COMPOSITE(0, "clk_uart4_src", mux_uart_src_p, 0, + PX30_CLKSEL_CON(43), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 8, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart4_np5", "clk_uart4_src", 0, + PX30_CLKSEL_CON(44), 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 9, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(45), 0, + PX30_CLKGATE_CON(11), 10, GFLAGS, + &px30_uart4_fracmux), + GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(11), 11, GFLAGS), + + COMPOSITE(0, "clk_uart5_src", mux_uart_src_p, 0, + PX30_CLKSEL_CON(46), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 12, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart5_np5", "clk_uart5_src", 0, + PX30_CLKSEL_CON(47), 0, 5, DFLAGS, + PX30_CLKGATE_CON(11), 13, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart5_frac", "clk_uart5_src", CLK_SET_RATE_PARENT, + PX30_CLKSEL_CON(48), 0, + PX30_CLKGATE_CON(11), 14, GFLAGS, + &px30_uart5_fracmux), + GATE(SCLK_UART5, "clk_uart5", "clk_uart5_mux", CLK_SET_RATE_PARENT, + PX30_CLKGATE_CON(11), 15, GFLAGS), + + COMPOSITE(SCLK_I2C0, "clk_i2c0", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(49), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(12), 0, GFLAGS), + COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(49), 15, 1, MFLAGS, 8, 7, DFLAGS, + PX30_CLKGATE_CON(12), 1, GFLAGS), + COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(50), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(12), 2, GFLAGS), + COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(50), 15, 1, MFLAGS, 8, 7, DFLAGS, + PX30_CLKGATE_CON(12), 3, GFLAGS), + COMPOSITE(SCLK_PWM0, "clk_pwm0", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(52), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(12), 5, GFLAGS), + COMPOSITE(SCLK_PWM1, "clk_pwm1", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(52), 15, 1, MFLAGS, 8, 7, DFLAGS, + PX30_CLKGATE_CON(12), 6, GFLAGS), + COMPOSITE(SCLK_SPI0, "clk_spi0", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(53), 7, 1, MFLAGS, 0, 7, DFLAGS, + PX30_CLKGATE_CON(12), 7, GFLAGS), + COMPOSITE(SCLK_SPI1, "clk_spi1", mux_gpll_xin24m_p, 0, + PX30_CLKSEL_CON(53), 15, 1, MFLAGS, 8, 7, DFLAGS, + PX30_CLKGATE_CON(12), 8, GFLAGS), + + GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0, + PX30_CLKGATE_CON(13), 0, GFLAGS), + GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0, + PX30_CLKGATE_CON(13), 1, GFLAGS), + GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0, + PX30_CLKGATE_CON(13), 2, GFLAGS), + GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0, + PX30_CLKGATE_CON(13), 3, GFLAGS), + GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0, + PX30_CLKGATE_CON(13), 4, GFLAGS), + GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0, + PX30_CLKGATE_CON(13), 5, GFLAGS), + + COMPOSITE_NOMUX(SCLK_TSADC, "clk_tsadc", "xin24m", 0, + PX30_CLKSEL_CON(54), 0, 11, DFLAGS, + PX30_CLKGATE_CON(12), 9, GFLAGS), + COMPOSITE_NOMUX(SCLK_SARADC, "clk_saradc", "xin24m", 0, + PX30_CLKSEL_CON(55), 0, 11, DFLAGS, + PX30_CLKGATE_CON(12), 10, GFLAGS), + COMPOSITE_NOMUX(SCLK_OTP, "clk_otp", "xin24m", 0, + PX30_CLKSEL_CON(56), 0, 3, DFLAGS, + PX30_CLKGATE_CON(12), 11, GFLAGS), + COMPOSITE_NOMUX(SCLK_OTP_USR, "clk_otp_usr", "clk_otp", 0, + PX30_CLKSEL_CON(56), 4, 2, DFLAGS, + PX30_CLKGATE_CON(13), 6, GFLAGS), + + GATE(0, "clk_cpu_boost", "xin24m", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(12), 12, GFLAGS), + + /* PD_CRYPTO */ + GATE(0, "aclk_crypto_pre", "aclk_bus_pre", 0, + PX30_CLKGATE_CON(8), 12, GFLAGS), + GATE(0, "hclk_crypto_pre", "hclk_bus_pre", 0, + PX30_CLKGATE_CON(8), 13, GFLAGS), + COMPOSITE(SCLK_CRYPTO, "clk_crypto", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(25), 6, 2, MFLAGS, 0, 5, DFLAGS, + PX30_CLKGATE_CON(8), 14, GFLAGS), + COMPOSITE(SCLK_CRYPTO_APK, "clk_crypto_apk", mux_gpll_cpll_npll_p, 0, + PX30_CLKSEL_CON(25), 14, 2, MFLAGS, 8, 5, DFLAGS, + PX30_CLKGATE_CON(8), 15, GFLAGS), + + /* + * Clock-Architecture Diagram 9 + */ + + /* PD_BUS_TOP */ + GATE(0, "pclk_top_niu", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 0, GFLAGS), + GATE(0, "pclk_top_cru", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 1, GFLAGS), + GATE(PCLK_OTP_PHY, "pclk_otp_phy", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 2, GFLAGS), + GATE(0, "pclk_ddrphy", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 3, GFLAGS), + GATE(PCLK_MIPIDSIPHY, "pclk_mipidsiphy", "pclk_top_pre", 0, PX30_CLKGATE_CON(16), 4, GFLAGS), + GATE(PCLK_MIPICSIPHY, "pclk_mipicsiphy", "pclk_top_pre", 0, PX30_CLKGATE_CON(16), 5, GFLAGS), + GATE(PCLK_USB_GRF, "pclk_usb_grf", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 6, GFLAGS), + GATE(0, "pclk_cpu_hoost", "pclk_top_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(16), 7, GFLAGS), + + /* PD_VI */ + GATE(0, "aclk_vi_niu", "aclk_vi_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(4), 15, GFLAGS), + GATE(ACLK_CIF, "aclk_cif", "aclk_vi_pre", 0, PX30_CLKGATE_CON(5), 1, GFLAGS), + GATE(ACLK_ISP, "aclk_isp", "aclk_vi_pre", 0, PX30_CLKGATE_CON(5), 3, GFLAGS), + GATE(0, "hclk_vi_niu", "hclk_vi_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(5), 0, GFLAGS), + GATE(HCLK_CIF, "hclk_cif", "hclk_vi_pre", 0, PX30_CLKGATE_CON(5), 2, GFLAGS), + GATE(HCLK_ISP, "hclk_isp", "hclk_vi_pre", 0, PX30_CLKGATE_CON(5), 4, GFLAGS), + + /* PD_VO */ + GATE(0, "aclk_vo_niu", "aclk_vo_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(3), 0, GFLAGS), + GATE(ACLK_VOPB, "aclk_vopb", "aclk_vo_pre", 0, PX30_CLKGATE_CON(3), 3, GFLAGS), + GATE(ACLK_RGA, "aclk_rga", "aclk_vo_pre", 0, PX30_CLKGATE_CON(3), 7, GFLAGS), + GATE(ACLK_VOPL, "aclk_vopl", "aclk_vo_pre", 0, PX30_CLKGATE_CON(3), 5, GFLAGS), + + GATE(0, "hclk_vo_niu", "hclk_vo_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(3), 1, GFLAGS), + GATE(HCLK_VOPB, "hclk_vopb", "hclk_vo_pre", 0, PX30_CLKGATE_CON(3), 4, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_vo_pre", 0, PX30_CLKGATE_CON(3), 8, GFLAGS), + GATE(HCLK_VOPL, "hclk_vopl", "hclk_vo_pre", 0, PX30_CLKGATE_CON(3), 6, GFLAGS), + + GATE(0, "pclk_vo_niu", "pclk_vo_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(3), 2, GFLAGS), + GATE(PCLK_MIPI_DSI, "pclk_mipi_dsi", "pclk_vo_pre", 0, PX30_CLKGATE_CON(3), 9, GFLAGS), + + /* PD_BUS */ + GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 8, GFLAGS), + GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 11, GFLAGS), + GATE(ACLK_GIC, "aclk_gic", "aclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 12, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0, PX30_CLKGATE_CON(13), 15, GFLAGS), + + GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 9, GFLAGS), + GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 14, GFLAGS), + GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 1, GFLAGS), + GATE(HCLK_I2S0, "hclk_i2s0", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 2, GFLAGS), + GATE(HCLK_I2S1, "hclk_i2s1", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 3, GFLAGS), + GATE(HCLK_I2S2, "hclk_i2s2", "hclk_bus_pre", 0, PX30_CLKGATE_CON(14), 4, GFLAGS), + + GATE(0, "pclk_bus_niu", "pclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(13), 10, GFLAGS), + GATE(PCLK_DCF, "pclk_dcf", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 0, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 5, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 6, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 7, GFLAGS), + GATE(PCLK_UART4, "pclk_uart4", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_UART5, "pclk_uart5", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 9, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 10, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 11, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 13, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 14, GFLAGS), + GATE(PCLK_PWM0, "pclk_pwm0", "pclk_bus_pre", 0, PX30_CLKGATE_CON(14), 15, GFLAGS), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 0, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 1, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 2, GFLAGS), + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 3, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 4, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 5, GFLAGS), + GATE(PCLK_OTP_NS, "pclk_otp_ns", "pclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(15), 6, GFLAGS), + GATE(PCLK_WDT_NS, "pclk_wdt_ns", "pclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(15), 7, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 8, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 9, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus_pre", 0, PX30_CLKGATE_CON(15), 10, GFLAGS), + GATE(0, "pclk_grf", "pclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(15), 11, GFLAGS), + GATE(0, "pclk_sgrf", "pclk_bus_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(15), 12, GFLAGS), + + /* PD_VPU */ + GATE(0, "hclk_vpu_niu", "hclk_vpu_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(4), 7, GFLAGS), + GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 0, PX30_CLKGATE_CON(4), 6, GFLAGS), + GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(4), 5, GFLAGS), + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, PX30_CLKGATE_CON(4), 4, GFLAGS), + + /* PD_CRYPTO */ + GATE(0, "hclk_crypto_niu", "hclk_crypto_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(9), 3, GFLAGS), + GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_crypto_pre", 0, PX30_CLKGATE_CON(9), 5, GFLAGS), + GATE(0, "aclk_crypto_niu", "aclk_crypto_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(9), 2, GFLAGS), + GATE(ACLK_CRYPTO, "aclk_crypto", "aclk_crypto_pre", 0, PX30_CLKGATE_CON(9), 4, GFLAGS), + + /* PD_SDCARD */ + GATE(0, "hclk_sdmmc_niu", "hclk_sdmmc_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(7), 0, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_sdmmc_pre", 0, PX30_CLKGATE_CON(7), 1, GFLAGS), + + /* PD_PERI */ + GATE(0, "aclk_peri_niu", "aclk_peri_pre", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(5), 9, GFLAGS), + + /* PD_MMC_NAND */ + GATE(HCLK_NANDC, "hclk_nandc", "hclk_mmc_nand", 0, PX30_CLKGATE_CON(5), 15, GFLAGS), + GATE(0, "hclk_mmc_nand_niu", "hclk_mmc_nand", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(6), 8, GFLAGS), + GATE(HCLK_SDIO, "hclk_sdio", "hclk_mmc_nand", 0, PX30_CLKGATE_CON(6), 9, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_mmc_nand", 0, PX30_CLKGATE_CON(6), 10, GFLAGS), + GATE(HCLK_SFC, "hclk_sfc", "hclk_mmc_nand", 0, PX30_CLKGATE_CON(6), 11, GFLAGS), + + /* PD_USB */ + GATE(0, "hclk_usb_niu", "hclk_usb", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(7), 4, GFLAGS), + GATE(HCLK_OTG, "hclk_otg", "hclk_usb", 0, PX30_CLKGATE_CON(7), 5, GFLAGS), + GATE(HCLK_HOST, "hclk_host", "hclk_usb", 0, PX30_CLKGATE_CON(7), 6, GFLAGS), + GATE(HCLK_HOST_ARB, "hclk_host_arb", "hclk_usb", CLK_IGNORE_UNUSED, PX30_CLKGATE_CON(7), 8, GFLAGS), + + /* PD_GMAC */ + GATE(0, "aclk_gmac_niu", "aclk_gmac_pre", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(8), 0, GFLAGS), + GATE(ACLK_GMAC, "aclk_gmac", "aclk_gmac_pre", 0, + PX30_CLKGATE_CON(8), 2, GFLAGS), + GATE(0, "pclk_gmac_niu", "pclk_gmac_pre", CLK_IGNORE_UNUSED, + PX30_CLKGATE_CON(8), 1, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_gmac_pre", 0, + PX30_CLKGATE_CON(8), 3, GFLAGS), +}; + +static struct rockchip_clk_branch px30_clk_pmu_branches[] __initdata = { + /* + * Clock-Architecture Diagram 2 + */ + + COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED, + PX30_PMU_CLKSEL_CON(1), 0, + PX30_PMU_CLKGATE_CON(0), 13, GFLAGS, + &px30_rtc32k_pmu_fracmux), + + COMPOSITE_NOMUX(XIN24M_DIV, "xin24m_div", "xin24m", CLK_IGNORE_UNUSED, + PX30_PMU_CLKSEL_CON(0), 8, 5, DFLAGS, + PX30_PMU_CLKGATE_CON(0), 12, GFLAGS), + + COMPOSITE_NOMUX(0, "clk_wifi_pmu_src", "gpll", 0, + PX30_PMU_CLKSEL_CON(2), 8, 6, DFLAGS, + PX30_PMU_CLKGATE_CON(0), 14, GFLAGS), + COMPOSITE_NODIV(SCLK_WIFI_PMU, "clk_wifi_pmu", mux_wifi_pmu_p, CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(2), 15, 1, MFLAGS, + PX30_PMU_CLKGATE_CON(0), 15, GFLAGS), + + COMPOSITE(0, "clk_uart0_pmu_src", mux_uart_src_p, 0, + PX30_PMU_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 5, DFLAGS, + PX30_PMU_CLKGATE_CON(1), 0, GFLAGS), + COMPOSITE_NOMUX_HALFDIV(0, "clk_uart0_np5", "clk_uart0_pmu_src", 0, + PX30_PMU_CLKSEL_CON(4), 0, 5, DFLAGS, + PX30_PMU_CLKGATE_CON(1), 1, GFLAGS), + COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_pmu_src", CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(5), 0, + PX30_PMU_CLKGATE_CON(1), 2, GFLAGS, + &px30_uart0_pmu_fracmux), + GATE(SCLK_UART0_PMU, "clk_uart0_pmu", "clk_uart0_pmu_mux", CLK_SET_RATE_PARENT, + PX30_PMU_CLKGATE_CON(1), 3, GFLAGS), + + GATE(SCLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", 0, + PX30_PMU_CLKGATE_CON(1), 4, GFLAGS), + + COMPOSITE_NOMUX(PCLK_PMU_PRE, "pclk_pmu_pre", "gpll", 0, + PX30_PMU_CLKSEL_CON(0), 0, 5, DFLAGS, + PX30_PMU_CLKGATE_CON(0), 0, GFLAGS), + + COMPOSITE_NOMUX(SCLK_REF24M_PMU, "clk_ref24m_pmu", "gpll", 0, + PX30_PMU_CLKSEL_CON(2), 0, 6, DFLAGS, + PX30_PMU_CLKGATE_CON(1), 8, GFLAGS), + COMPOSITE_NODIV(SCLK_USBPHY_REF, "clk_usbphy_ref", mux_usbphy_ref_p, CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(2), 6, 1, MFLAGS, + PX30_PMU_CLKGATE_CON(1), 9, GFLAGS), + COMPOSITE_NODIV(SCLK_MIPIDSIPHY_REF, "clk_mipidsiphy_ref", mux_mipidsiphy_ref_p, CLK_SET_RATE_PARENT, + PX30_PMU_CLKSEL_CON(2), 7, 1, MFLAGS, + PX30_PMU_CLKGATE_CON(1), 10, GFLAGS), + + /* + * Clock-Architecture Diagram 9 + */ + + /* PD_PMU */ + GATE(0, "pclk_pmu_niu", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 1, GFLAGS), + GATE(0, "pclk_pmu_sgrf", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 2, GFLAGS), + GATE(0, "pclk_pmu_grf", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 3, GFLAGS), + GATE(0, "pclk_pmu", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "pclk_pmu_mem", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 5, GFLAGS), + GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pclk_pmu_pre", 0, PX30_PMU_CLKGATE_CON(0), 6, GFLAGS), + GATE(PCLK_UART0_PMU, "pclk_uart0_pmu", "pclk_pmu_pre", 0, PX30_PMU_CLKGATE_CON(0), 7, GFLAGS), + GATE(0, "pclk_cru_pmu", "pclk_pmu_pre", CLK_IGNORE_UNUSED, PX30_PMU_CLKGATE_CON(0), 8, GFLAGS), +}; + +static const char *const px30_pmucru_critical_clocks[] __initconst = { + "aclk_bus_pre", + "pclk_bus_pre", + "hclk_bus_pre", + "aclk_peri_pre", + "hclk_peri_pre", + "aclk_gpu_niu", + "pclk_top_pre", + "pclk_pmu_pre", + "hclk_usb_niu", + "pll_npll", + "usb480m", + "clk_uart2", + "pclk_uart2", +}; + +static void __init px30_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + struct clk *clk; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); + return; + } + + /* aclk_dmac is controlled by sgrf_soc_con1[11]. */ + clk = clk_register_fixed_factor(NULL, "aclk_dmac", "aclk_bus_pre", 0, 1, 1); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock aclk_dmac: %ld\n", + __func__, PTR_ERR(clk)); + else + rockchip_clk_add_lookup(ctx, clk, ACLK_DMAC); + + rockchip_clk_register_plls(ctx, px30_pll_clks, + ARRAY_SIZE(px30_pll_clks), + PX30_GRF_SOC_STATUS0); + rockchip_clk_register_branches(ctx, px30_clk_branches, + ARRAY_SIZE(px30_clk_branches)); + + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &px30_cpuclk_data, px30_cpuclk_rates, + ARRAY_SIZE(px30_cpuclk_rates)); + + rockchip_register_softrst(np, 12, reg_base + PX30_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(ctx, PX30_GLB_SRST_FST, NULL); + + rockchip_clk_of_add_provider(np, ctx); +} +CLK_OF_DECLARE(px30_cru, "rockchip,px30-cru", px30_clk_init); + +static void __init px30_pmu_clk_init(struct device_node *np) +{ + struct rockchip_clk_provider *ctx; + void __iomem *reg_base; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru pmu region\n", __func__); + return; + } + + ctx = rockchip_clk_init(np, reg_base, CLKPMU_NR_CLKS); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip pmu clk init failed\n", __func__); + return; + } + + rockchip_clk_register_plls(ctx, px30_pmu_pll_clks, + ARRAY_SIZE(px30_pmu_pll_clks), PX30_GRF_SOC_STATUS0); + + rockchip_clk_register_branches(ctx, px30_clk_pmu_branches, + ARRAY_SIZE(px30_clk_pmu_branches)); + + rockchip_clk_protect_critical(px30_pmucru_critical_clocks, + ARRAY_SIZE(px30_pmucru_critical_clocks)); + + rockchip_clk_of_add_provider(np, ctx); +} +CLK_OF_DECLARE(px30_cru_pmu, "rockchip,px30-pmucru", px30_pmu_clk_init); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 23c569a875d4..6b53fff4cc96 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -34,7 +34,46 @@ struct clk; #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) -/* register positions shared by RV1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */ +/* register positions shared by PX30, RV1108, RK2928, RK3036, RK3066, RK3188 and RK3228 */ +#define BOOST_PLL_H_CON(x) ((x) * 0x4) +#define BOOST_CLK_CON 0x0008 +#define BOOST_BOOST_CON 0x000c +#define BOOST_SWITCH_CNT 0x0010 +#define BOOST_HIGH_PERF_CNT0 0x0014 +#define BOOST_HIGH_PERF_CNT1 0x0018 +#define BOOST_STATIS_THRESHOLD 0x001c +#define BOOST_SHORT_SWITCH_CNT 0x0020 +#define BOOST_SWITCH_THRESHOLD 0x0024 +#define BOOST_FSM_STATUS 0x0028 +#define BOOST_PLL_L_CON(x) ((x) * 0x4 + 0x2c) +#define BOOST_RECOVERY_MASK 0x1 +#define BOOST_RECOVERY_SHIFT 1 +#define BOOST_SW_CTRL_MASK 0x1 +#define BOOST_SW_CTRL_SHIFT 2 +#define BOOST_LOW_FREQ_EN_MASK 0x1 +#define BOOST_LOW_FREQ_EN_SHIFT 3 +#define BOOST_BUSY_STATE BIT(8) + +#define PX30_PLL_CON(x) ((x) * 0x4) +#define PX30_CLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define PX30_CLKGATE_CON(x) ((x) * 0x4 + 0x200) +#define PX30_GLB_SRST_FST 0xb8 +#define PX30_GLB_SRST_SND 0xbc +#define PX30_SOFTRST_CON(x) ((x) * 0x4 + 0x300) +#define PX30_MODE_CON 0xa0 +#define PX30_MISC_CON 0xa4 +#define PX30_SDMMC_CON0 0x380 +#define PX30_SDMMC_CON1 0x384 +#define PX30_SDIO_CON0 0x388 +#define PX30_SDIO_CON1 0x38c +#define PX30_EMMC_CON0 0x390 +#define PX30_EMMC_CON1 0x394 + +#define PX30_PMU_PLL_CON(x) ((x) * 0x4) +#define PX30_PMU_CLKSEL_CON(x) ((x) * 0x4 + 0x40) +#define PX30_PMU_CLKGATE_CON(x) ((x) * 0x4 + 0x80) +#define PX30_PMU_MODE 0x0020 + #define RV1108_PLL_CON(x) ((x) * 0x4) #define RV1108_CLKSEL_CON(x) ((x) * 0x4 + 0x60) #define RV1108_CLKGATE_CON(x) ((x) * 0x4 + 0x120) From 2772ffd979baa1893c1fa75041c59b507716dcc7 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 26 Jun 2018 08:28:09 -0500 Subject: [PATCH 27/85] clk: socfpga: stratix10: fix the parents of mpu_free_clk Add a clock mux that is used as a parent for the mpu_free_clk. Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-s10.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 72714633e39c..a15769f9985b 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -37,6 +37,11 @@ static const char * const s2f_usr0_mux[] = {"f2s_free_clk", "boot_clk"}; static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"}; static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"}; +static const char * const mpu_free_mux[] = {"main_mpu_base_clk", + "peri_mpu_base_clk", + "osc1", "cb_intosc_hs_div2_clk", + "f2s_free_clk"}; + /* clocks in AO (always on) controller */ static const struct stratix10_pll_clock s10_pll_clks[] = { { STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0, @@ -57,7 +62,7 @@ static const struct stratix10_perip_c_clock s10_main_perip_c_clks[] = { }; static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = { - { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux), 0, 0x48, 0, 0, 0}, { STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux), 0, 0x4C, 0, 0, 0}, From 51b9a379a843c288b07b501784a5cc52b2c5aa69 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 26 Jun 2018 08:28:10 -0500 Subject: [PATCH 28/85] clk: socfpga: stratix10: fix the sdmmc_free_clk mux The first parent of the sdmmc_free_clk should be the main_sdmmc_clk. Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-s10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index a15769f9985b..5b238fc314ac 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -28,7 +28,7 @@ static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"}; static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"}; static const char * const emac_ptp_free_mux[] = {"peri_emac_ptp_clk", "boot_clk"}; static const char * const gpio_db_free_mux[] = {"peri_gpio_db_clk", "boot_clk"}; -static const char * const sdmmc_free_mux[] = {"peri_sdmmc_clk", "boot_clk"}; +static const char * const sdmmc_free_mux[] = {"main_sdmmc_clk", "boot_clk"}; static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk"}; static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"}; static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",}; From 5f273c0d9facfea124f6dea9de41775085056cc2 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Jun 2018 17:12:35 +0300 Subject: [PATCH 29/85] dt-bindings: clk: at91: add an I2S mux clock The I2S mux clock can be used to select the I2S input clock. The available parents are the peripheral and the generated clocks. Signed-off-by: Codrin Ciubotariu Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/at91-clock.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index 51c259a92d02..d0adbf5ae144 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -91,6 +91,9 @@ Required properties: at91 audio pll output on AUDIOPLLCLK that feeds the PMC and can be used by peripheral clock or generic clock + "atmel,sama5d2-clk-i2s-mux" (under pmc node): + at91 I2S clock source selection + Required properties for SCKC node: - reg : defines the IO memory reserved for the SCKC. - #size-cells : shall be 0 (reg is used to encode clk id). @@ -507,3 +510,35 @@ For example: atmel,clk-output-range = <0 83000000>; }; }; + +Required properties for I2S mux clocks: +- #size-cells : shall be 0 (reg is used to encode I2S bus id). +- #address-cells : shall be 1 (reg is used to encode I2S bus id). +- name: device tree node describing a specific mux clock. + * #clock-cells : from common clock binding; shall be set to 0. + * clocks : shall be the mux clock parent phandles; shall be 2 phandles: + peripheral and generated clock; the first phandle shall belong to the + peripheral clock and the second one shall belong to the generated + clock; "clock-indices" property can be user to specify + the correct order. + * reg: I2S bus id of the corresponding mux clock. + e.g. reg = <0>; for i2s0, reg = <1>; for i2s1 + +For example: + i2s_clkmux { + compatible = "atmel,sama5d2-clk-i2s-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2s0muxck: i2s0_muxclk { + clocks = <&i2s0_clk>, <&i2s0_gclk>; + #clock-cells = <0>; + reg = <0>; + }; + + i2s1muxck: i2s1_muxclk { + clocks = <&i2s1_clk>, <&i2s1_gclk>; + #clock-cells = <0>; + reg = <1>; + }; + }; From 96e4ea8c253d12079db4d7174990455b4bbf0c87 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Jun 2018 17:12:36 +0300 Subject: [PATCH 30/85] clk: at91: add I2S clock mux driver This driver is a simple muxing driver that controls the I2S's clock input by using syscon/regmap to change the parent. The available inputs can be peripheral clock and generated clock. Signed-off-by: Codrin Ciubotariu [sboyd@kernel.org: Fix SPDX tag comment style] Signed-off-by: Stephen Boyd --- arch/arm/mach-at91/Kconfig | 4 ++ drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-i2s-mux.c | 116 +++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/clk/at91/clk-i2s-mux.c diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 1254bf9d91b4..903f23c309df 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -27,6 +27,7 @@ config SOC_SAMA5D2 select HAVE_AT91_H32MX select HAVE_AT91_GENERATED_CLK select HAVE_AT91_AUDIO_PLL + select HAVE_AT91_I2S_MUX_CLK select PINCTRL_AT91PIO4 help Select this if ou are using one of Microchip's SAMA5D2 family SoC. @@ -129,6 +130,9 @@ config HAVE_AT91_GENERATED_CLK config HAVE_AT91_AUDIO_PLL bool +config HAVE_AT91_I2S_MUX_CLK + bool + config SOC_SAM_V4_V5 bool diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 082596f37c1d..facc169ebb68 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o +obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c new file mode 100644 index 000000000000..f0c3c3079f04 --- /dev/null +++ b/drivers/clk/at91/clk-i2s-mux.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Microchip Technology Inc, + * Codrin Ciubotariu + * + * + */ + +#include +#include +#include +#include +#include + +#include + +#define I2S_BUS_NR 2 + +struct clk_i2s_mux { + struct clk_hw hw; + struct regmap *regmap; + u8 bus_id; +}; + +#define to_clk_i2s_mux(hw) container_of(hw, struct clk_i2s_mux, hw) + +static u8 clk_i2s_mux_get_parent(struct clk_hw *hw) +{ + struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); + u32 val; + + regmap_read(mux->regmap, AT91_SFR_I2SCLKSEL, &val); + + return (val & BIT(mux->bus_id)) >> mux->bus_id; +} + +static int clk_i2s_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); + + return regmap_update_bits(mux->regmap, AT91_SFR_I2SCLKSEL, + BIT(mux->bus_id), index << mux->bus_id); +} + +static const struct clk_ops clk_i2s_mux_ops = { + .get_parent = clk_i2s_mux_get_parent, + .set_parent = clk_i2s_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk_hw * __init +at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, + const char * const *parent_names, + unsigned int num_parents, u8 bus_id) +{ + struct clk_init_data init = {}; + struct clk_i2s_mux *i2s_ck; + int ret; + + i2s_ck = kzalloc(sizeof(*i2s_ck), GFP_KERNEL); + if (!i2s_ck) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_i2s_mux_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + + i2s_ck->hw.init = &init; + i2s_ck->bus_id = bus_id; + i2s_ck->regmap = regmap; + + ret = clk_hw_register(NULL, &i2s_ck->hw); + if (ret) { + kfree(i2s_ck); + return ERR_PTR(ret); + } + + return &i2s_ck->hw; +} + +static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) +{ + struct regmap *regmap_sfr; + u8 bus_id; + const char *parent_names[2]; + struct device_node *i2s_mux_np; + struct clk_hw *hw; + int ret; + + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + return; + + for_each_child_of_node(np, i2s_mux_np) { + if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) + continue; + + if (bus_id > I2S_BUS_NR) + continue; + + ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); + if (ret != 2) + continue; + + hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, + parent_names, 2, bus_id); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); + } +} + +CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", + of_sama5d2_clk_i2s_mux_setup); From 18df02fb79cb20ba4de1e02e1df41ba83f8b9bec Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 17 Jun 2018 14:05:34 +0200 Subject: [PATCH 31/85] dts: clk: add devicetree bindings for MAX9485 This patch adds the devicetree bindings for MAX9485, a programmable audio clock generator. Signed-off-by: Daniel Mack Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/maxim,max9485.txt | 59 +++++++++++++++++++ include/dt-bindings/clock/maxim,max9485.h | 18 ++++++ 2 files changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/maxim,max9485.txt create mode 100644 include/dt-bindings/clock/maxim,max9485.h diff --git a/Documentation/devicetree/bindings/clock/maxim,max9485.txt b/Documentation/devicetree/bindings/clock/maxim,max9485.txt new file mode 100644 index 000000000000..61bec1100a94 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/maxim,max9485.txt @@ -0,0 +1,59 @@ +Devicetree bindings for Maxim MAX9485 Programmable Audio Clock Generator + +This device exposes 4 clocks in total: + +- MAX9485_MCLKOUT: A gated, buffered output of the input clock of 27 MHz +- MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete + frequencies +- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT + +MAX9485_CLKOUT[1,2] are children of MAX9485_CLKOUT which upchain all rate set +requests. + +Required properties: +- compatible: "maxim,max9485" +- clocks: Input clock, must provice 27.000 MHz +- clock-names: Must be set to "xclk" +- #clock-cells: From common clock binding; shall be set to 1 + +Optional properties: +- reset-gpios: GPIO descriptor connected to the #RESET input pin +- vdd-supply: A regulator node for Vdd +- clock-output-names: Name of output clocks, as defined in common clock + bindings + +If not explicitly set, the output names are "mclkout", "clkout", "clkout1" +and "clkout2". + +Clocks are defined as preprocessor macros in the dt-binding header. + +Example: + + #include + + xo-27mhz: xo-27mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + + &i2c0 { + max9485: audio-clock@63 { + reg = <0x63>; + compatible = "maxim,max9485"; + clock-names = "xclk"; + clocks = <&xo-27mhz>; + reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + vdd-supply = <&3v3-reg>; + #clock-cells = <1>; + }; + }; + + // Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "foo-input-clk"; + clocks = <&max9485 MAX9485_CLKOUT1>; + }; diff --git a/include/dt-bindings/clock/maxim,max9485.h b/include/dt-bindings/clock/maxim,max9485.h new file mode 100644 index 000000000000..185b09ce1869 --- /dev/null +++ b/include/dt-bindings/clock/maxim,max9485.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DT_BINDINGS_MAX9485_CLK_H +#define __DT_BINDINGS_MAX9485_CLK_H + +#define MAX9485_MCLKOUT 0 +#define MAX9485_CLKOUT 1 +#define MAX9485_CLKOUT1 2 +#define MAX9485_CLKOUT2 3 + +#endif /* __DT_BINDINGS_MAX9485_CLK_H */ From 574f4e80d59e5c669c0729718525df8bac5e4d78 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 27 Jun 2018 14:14:58 +0200 Subject: [PATCH 32/85] clk: ingenic: Fix incorrect data for the i2s clock The register field for configuring the divider for the i2s clock occupies the bits [8-0], which means 9 bits and not 8. Signed-off-by: Paul Cercueil Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/jz4740-cgu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index 32fcc75f6f77..bc073dd4470d 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -134,7 +134,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 31, 1 }, - .div = { CGU_REG_I2SCDR, 0, 1, 8, -1, -1, -1 }, + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 6 }, }, From 2b555a4b9caecfcab1b2aade176df795ceceaefa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 27 Jun 2018 14:14:59 +0200 Subject: [PATCH 33/85] clk: ingenic: Add missing flag for UDC clock The UDC clock of the JZ4740 SoC can be gated, but the data structure representing it was missing the CGU_CLK_GATE flag to make it work. Signed-off-by: Paul Cercueil Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/jz4740-cgu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index bc073dd4470d..4479c102e899 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -161,7 +161,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { }, [JZ4740_CLK_UDC] = { - "udc", CGU_CLK_MUX | CGU_CLK_DIV, + "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 29, 1 }, .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, From 33f5104624b96c6514621e63909b5703276b4dac Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 6 Jul 2018 20:53:03 +0200 Subject: [PATCH 34/85] clk: Add driver for MAX9485 This patch adds a driver for MAX9485, a programmable audio clock generator. The device requires a 27.000 MHz clock input. It can provide a gated buffered output of its input clock and two gated outputs of a PLL that can generate one out of 16 discrete frequencies. There is only one PLL however, so the two gated outputs will always have the same frequency but they can be switched individually. The driver for this device exposes 4 clocks in total: - MAX9485_MCLKOUT: A gated, buffered output of the input clock - MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete frequencies - MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT Some PLL output frequencies can be achieved with different register settings. The driver will select the one with lowest jitter in such cases. Signed-off-by: Daniel Mack [sboyd@kernel.org: Use local variable for val in max9485_clkout_recalc_rate() and shorten line of max9485_of_clk_get()] Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 1 + drivers/clk/clk-max9485.c | 387 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 394 insertions(+) create mode 100644 drivers/clk/clk-max9485.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 721572a8c429..292056bbb30e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -45,6 +45,12 @@ config COMMON_CLK_MAX77686 This driver supports Maxim 77620/77686/77802 crystal oscillator clock. +config COMMON_CLK_MAX9485 + tristate "Maxim 9485 Programmable Clock Generator" + depends on I2C + help + This driver supports Maxim 9485 Programmable Audio Clock Generator + config COMMON_CLK_RK808 tristate "Clock driver for RK805/RK808/RK818" depends on MFD_RK808 diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ae40cbe770f0..24fc2b634362 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o +obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o diff --git a/drivers/clk/clk-max9485.c b/drivers/clk/clk-max9485.c new file mode 100644 index 000000000000..5e80f3d090f3 --- /dev/null +++ b/drivers/clk/clk-max9485.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX9485_NUM_CLKS 4 + +/* This chip has only one register of 8 bit width. */ + +#define MAX9485_FS_12KHZ (0 << 0) +#define MAX9485_FS_32KHZ (1 << 0) +#define MAX9485_FS_44_1KHZ (2 << 0) +#define MAX9485_FS_48KHZ (3 << 0) + +#define MAX9485_SCALE_256 (0 << 2) +#define MAX9485_SCALE_384 (1 << 2) +#define MAX9485_SCALE_768 (2 << 2) + +#define MAX9485_DOUBLE BIT(4) +#define MAX9485_CLKOUT1_ENABLE BIT(5) +#define MAX9485_CLKOUT2_ENABLE BIT(6) +#define MAX9485_MCLK_ENABLE BIT(7) +#define MAX9485_FREQ_MASK 0x1f + +struct max9485_rate { + unsigned long out; + u8 reg_value; +}; + +/* + * Ordered by frequency. For frequency the hardware can generate with + * multiple settings, the one with lowest jitter is listed first. + */ +static const struct max9485_rate max9485_rates[] = { + { 3072000, MAX9485_FS_12KHZ | MAX9485_SCALE_256 }, + { 4608000, MAX9485_FS_12KHZ | MAX9485_SCALE_384 }, + { 8192000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 }, + { 9126000, MAX9485_FS_12KHZ | MAX9485_SCALE_768 }, + { 11289600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 }, + { 12288000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 }, + { 12288000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 }, + { 16384000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 16934400, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 }, + { 18384000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 }, + { 22579200, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 }, + { 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 }, + { 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 }, + { 49152000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { 67737600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { 73728000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { } /* sentinel */ +}; + +struct max9485_driver_data; + +struct max9485_clk_hw { + struct clk_hw hw; + struct clk_init_data init; + u8 enable_bit; + struct max9485_driver_data *drvdata; +}; + +struct max9485_driver_data { + struct clk *xclk; + struct i2c_client *client; + u8 reg_value; + struct regulator *supply; + struct gpio_desc *reset_gpio; + struct max9485_clk_hw hw[MAX9485_NUM_CLKS]; +}; + +static inline struct max9485_clk_hw *to_max9485_clk(struct clk_hw *hw) +{ + return container_of(hw, struct max9485_clk_hw, hw); +} + +static int max9485_update_bits(struct max9485_driver_data *drvdata, + u8 mask, u8 value) +{ + int ret; + + drvdata->reg_value &= ~mask; + drvdata->reg_value |= value; + + dev_dbg(&drvdata->client->dev, + "updating mask 0x%02x value 0x%02x -> 0x%02x\n", + mask, value, drvdata->reg_value); + + ret = i2c_master_send(drvdata->client, + &drvdata->reg_value, + sizeof(drvdata->reg_value)); + + return ret < 0 ? ret : 0; +} + +static int max9485_clk_prepare(struct clk_hw *hw) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + + return max9485_update_bits(clk_hw->drvdata, + clk_hw->enable_bit, + clk_hw->enable_bit); +} + +static void max9485_clk_unprepare(struct clk_hw *hw) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + + max9485_update_bits(clk_hw->drvdata, clk_hw->enable_bit, 0); +} + +/* + * CLKOUT - configurable clock output + */ +static int max9485_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + const struct max9485_rate *entry; + + for (entry = max9485_rates; entry->out != 0; entry++) + if (entry->out == rate) + break; + + if (entry->out == 0) + return -EINVAL; + + return max9485_update_bits(clk_hw->drvdata, + MAX9485_FREQ_MASK, + entry->reg_value); +} + +static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + struct max9485_driver_data *drvdata = clk_hw->drvdata; + u8 val = drvdata->reg_value & MAX9485_FREQ_MASK; + const struct max9485_rate *entry; + + for (entry = max9485_rates; entry->out != 0; entry++) + if (val == entry->reg_value) + return entry->out; + + return 0; +} + +static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + const struct max9485_rate *curr, *prev = NULL; + + for (curr = max9485_rates; curr->out != 0; curr++) { + /* Exact matches */ + if (curr->out == rate) + return rate; + + /* + * Find the first entry that has a frequency higher than the + * requested one. + */ + if (curr->out > rate) { + unsigned int mid; + + /* + * If this is the first entry, clamp the value to the + * lowest possible frequency. + */ + if (!prev) + return curr->out; + + /* + * Otherwise, determine whether the previous entry or + * current one is closer. + */ + mid = prev->out + ((curr->out - prev->out) / 2); + + return (mid > rate) ? prev->out : curr->out; + } + + prev = curr; + } + + /* If the last entry was still too high, clamp the value */ + return prev->out; +} + +struct max9485_clk { + const char *name; + int parent_index; + const struct clk_ops ops; + u8 enable_bit; +}; + +static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = { + [MAX9485_MCLKOUT] = { + .name = "mclkout", + .parent_index = -1, + .enable_bit = MAX9485_MCLK_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, + [MAX9485_CLKOUT] = { + .name = "clkout", + .parent_index = -1, + .ops = { + .set_rate = max9485_clkout_set_rate, + .round_rate = max9485_clkout_round_rate, + .recalc_rate = max9485_clkout_recalc_rate, + }, + }, + [MAX9485_CLKOUT1] = { + .name = "clkout1", + .parent_index = MAX9485_CLKOUT, + .enable_bit = MAX9485_CLKOUT1_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, + [MAX9485_CLKOUT2] = { + .name = "clkout2", + .parent_index = MAX9485_CLKOUT, + .enable_bit = MAX9485_CLKOUT2_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, +}; + +static struct clk_hw * +max9485_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct max9485_driver_data *drvdata = data; + unsigned int idx = clkspec->args[0]; + + return &drvdata->hw[idx].hw; +} + +static int max9485_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max9485_driver_data *drvdata; + struct device *dev = &client->dev; + const char *xclk_name; + int i, ret; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(drvdata->xclk)) + return PTR_ERR(drvdata->xclk); + + xclk_name = __clk_get_name(drvdata->xclk); + + drvdata->supply = devm_regulator_get(dev, "vdd"); + if (IS_ERR(drvdata->supply)) + return PTR_ERR(drvdata->supply); + + ret = regulator_enable(drvdata->supply); + if (ret < 0) + return ret; + + drvdata->reset_gpio = + devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(drvdata->reset_gpio)) + return PTR_ERR(drvdata->reset_gpio); + + i2c_set_clientdata(client, drvdata); + drvdata->client = client; + + ret = i2c_master_recv(drvdata->client, &drvdata->reg_value, + sizeof(drvdata->reg_value)); + if (ret < 0) { + dev_warn(dev, "Unable to read device register: %d\n", ret); + return ret; + } + + for (i = 0; i < MAX9485_NUM_CLKS; i++) { + int parent_index = max9485_clks[i].parent_index; + const char *name; + + if (of_property_read_string_index(dev->of_node, + "clock-output-names", + i, &name) == 0) { + drvdata->hw[i].init.name = name; + } else { + drvdata->hw[i].init.name = max9485_clks[i].name; + } + + drvdata->hw[i].init.ops = &max9485_clks[i].ops; + drvdata->hw[i].init.num_parents = 1; + drvdata->hw[i].init.flags = 0; + + if (parent_index > 0) { + drvdata->hw[i].init.parent_names = + &drvdata->hw[parent_index].init.name; + drvdata->hw[i].init.flags |= CLK_SET_RATE_PARENT; + } else { + drvdata->hw[i].init.parent_names = &xclk_name; + } + + drvdata->hw[i].enable_bit = max9485_clks[i].enable_bit; + drvdata->hw[i].hw.init = &drvdata->hw[i].init; + drvdata->hw[i].drvdata = drvdata; + + ret = devm_clk_hw_register(dev, &drvdata->hw[i].hw); + if (ret < 0) + return ret; + } + + return devm_of_clk_add_hw_provider(dev, max9485_of_clk_get, drvdata); +} + +static int __maybe_unused max9485_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max9485_driver_data *drvdata = i2c_get_clientdata(client); + + gpiod_set_value_cansleep(drvdata->reset_gpio, 0); + + return 0; +} + +static int __maybe_unused max9485_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max9485_driver_data *drvdata = i2c_get_clientdata(client); + int ret; + + gpiod_set_value_cansleep(drvdata->reset_gpio, 1); + + ret = i2c_master_send(client, &drvdata->reg_value, + sizeof(drvdata->reg_value)); + + return ret < 0 ? ret : 0; +} + +static const struct dev_pm_ops max9485_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max9485_suspend, max9485_resume) +}; + +static const struct of_device_id max9485_dt_ids[] = { + { .compatible = "maxim,max9485", }, + { } +}; +MODULE_DEVICE_TABLE(of, max9485_dt_ids); + +static const struct i2c_device_id max9485_i2c_ids[] = { + { .name = "max9485", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max9485_i2c_ids); + +static struct i2c_driver max9485_driver = { + .driver = { + .name = "max9485", + .pm = &max9485_pm_ops, + .of_match_table = max9485_dt_ids, + }, + .probe = max9485_i2c_probe, + .id_table = max9485_i2c_ids, +}; +module_i2c_driver(max9485_driver); + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("MAX9485 Programmable Audio Clock Generator"); +MODULE_LICENSE("GPL v2"); From fc20654389364a55eeab837244b24f8da75009f6 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 27 Jun 2018 21:41:23 +0200 Subject: [PATCH 35/85] clk: pxa: export 32kHz PLL This clock is especially used by the RTC driver, so export it so that devicetree users can use it. Signed-off-by: Robert Jarzmik Signed-off-by: Stephen Boyd --- drivers/clk/pxa/clk-pxa25x.c | 6 ++++-- drivers/clk/pxa/clk-pxa27x.c | 7 ++++--- drivers/clk/pxa/clk-pxa3xx.c | 7 ++++--- include/dt-bindings/clock/pxa-clock.h | 3 ++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c index 6416c1f8e632..e88f8e01fe3a 100644 --- a/drivers/clk/pxa/clk-pxa25x.c +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -292,8 +292,10 @@ static void __init pxa25x_register_plls(void) { clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL, CLK_GET_RATE_NOCACHE, 3686400); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, 32768); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768)); clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz", 0, 26, 1); diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index 25a30194d27a..d40b63e7bbce 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -314,9 +314,10 @@ static void __init pxa27x_register_plls(void) clk_register_fixed_rate(NULL, "osc_13mhz", NULL, CLK_GET_RATE_NOCACHE, 13 * MHz); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, - 32768 * KHz); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768 * KHz)); clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); } diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c index 2d126df2bccd..7aa120c3bd08 100644 --- a/drivers/clk/pxa/clk-pxa3xx.c +++ b/drivers/clk/pxa/clk-pxa3xx.c @@ -286,9 +286,10 @@ static void __init pxa3xx_register_plls(void) clk_register_fixed_rate(NULL, "osc_13mhz", NULL, CLK_GET_RATE_NOCACHE, 13 * MHz); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, - 32768); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768)); clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL, CLK_GET_RATE_NOCACHE, 120 * MHz); diff --git a/include/dt-bindings/clock/pxa-clock.h b/include/dt-bindings/clock/pxa-clock.h index e65803b1dc7e..0b0fd2b01538 100644 --- a/include/dt-bindings/clock/pxa-clock.h +++ b/include/dt-bindings/clock/pxa-clock.h @@ -72,6 +72,7 @@ #define CLK_USIM 58 #define CLK_USIM1 59 #define CLK_USMI0 60 -#define CLK_MAX 61 +#define CLK_OSC32k768 61 +#define CLK_MAX 62 #endif From cd88259a7215e0737f8ef2c2842f41922ae87d8d Mon Sep 17 00:00:00 2001 From: Lei YU Date: Tue, 26 Jun 2018 09:55:25 +0800 Subject: [PATCH 36/85] clk: aspeed: Fix SDCLK name The SDCLK was named SDCLKCLK, and no one has used this yet. Fix it. Signed-off-by: Lei YU Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/clk-aspeed.c | 2 +- include/dt-bindings/clock/aspeed-clock.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 38b366b00c57..f49c6842c604 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -109,7 +109,7 @@ static const struct aspeed_gate_data aspeed_gates[] = { [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ - [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ + [ASPEED_CLK_GATE_SDCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ }; diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h index 44761849fcbe..f43738607d77 100644 --- a/include/dt-bindings/clock/aspeed-clock.h +++ b/include/dt-bindings/clock/aspeed-clock.h @@ -25,7 +25,7 @@ #define ASPEED_CLK_GATE_RSACLK 19 #define ASPEED_CLK_GATE_UART3CLK 20 #define ASPEED_CLK_GATE_UART4CLK 21 -#define ASPEED_CLK_GATE_SDCLKCLK 22 +#define ASPEED_CLK_GATE_SDCLK 22 #define ASPEED_CLK_GATE_LHCCLK 23 #define ASPEED_CLK_HPLL 24 #define ASPEED_CLK_AHB 25 From 9d8108f9f3cb996a9677223fcd1feeb1f3e05566 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 22 Jun 2018 14:32:33 +0800 Subject: [PATCH 37/85] clk: imx6sll: add GPIO LPCGs According to Reference Manual Rev.0, 06/2017, there are GPIO LPCGs defined in CCM CCGRs, add them into clock tree. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sll.c | 6 ++++++ include/dt-bindings/clock/imx6sll-clock.h | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 3651c77fbabe..627064597af9 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -253,6 +253,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10); clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); + clks[IMX6SLL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30); /* CCGR1 */ clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -267,13 +268,17 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); + clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); /* CCGR2 */ + clks[IMX6SLL_CLK_GPIO6] = imx_clk_gate2("gpio6", "ipg", base + 0x70, 0); clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2); clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6SLL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26); clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); @@ -283,6 +288,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4); clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4); clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6SLL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); diff --git a/include/dt-bindings/clock/imx6sll-clock.h b/include/dt-bindings/clock/imx6sll-clock.h index 151111e68f4f..1036475f997d 100644 --- a/include/dt-bindings/clock/imx6sll-clock.h +++ b/include/dt-bindings/clock/imx6sll-clock.h @@ -197,6 +197,13 @@ #define IMX6SLL_CLK_EXTERN_AUDIO_PODF 171 #define IMX6SLL_CLK_EXTERN_AUDIO 172 -#define IMX6SLL_CLK_END 173 +#define IMX6SLL_CLK_GPIO1 173 +#define IMX6SLL_CLK_GPIO2 174 +#define IMX6SLL_CLK_GPIO3 175 +#define IMX6SLL_CLK_GPIO4 176 +#define IMX6SLL_CLK_GPIO5 177 +#define IMX6SLL_CLK_GPIO6 178 + +#define IMX6SLL_CLK_END 179 #endif /* __DT_BINDINGS_CLOCK_IMX6SLL_H */ From ed235d556945f46dbac84227f6f1467d397e39a3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 4 Jul 2018 10:49:23 -0300 Subject: [PATCH 38/85] clk: imx51-imx53: Annotate critical clocks as CLK_IS_CRITICAL Instead of explicitly enabling critical clocks via clk_prepare_enable(), let's use the standard CLK_IS_CRITICAL flag instead, which makes the code a bit shorter. Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx51-imx53.c | 43 ++++++++++--------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index caa8bd40692c..346a53b48f9c 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -175,13 +175,13 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", MXC_CCM_CBCMR, 0, 1, per_root_sel, ARRAY_SIZE(per_root_sel)); clk[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3); - clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28); - clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24); - clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26); - clk[IMX5_CLK_TMAX1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0); - clk[IMX5_CLK_TMAX2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2); - clk[IMX5_CLK_TMAX3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4); - clk[IMX5_CLK_SPBA] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0); + clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2_flags("ahb_max", "ahb", MXC_CCM_CCGR0, 28, CLK_IS_CRITICAL); + clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", MXC_CCM_CCGR0, 24, CLK_IS_CRITICAL); + clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", MXC_CCM_CCGR0, 26, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX1] = imx_clk_gate2_flags("tmax1", "ahb", MXC_CCM_CCGR1, 0, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX2] = imx_clk_gate2_flags("tmax2", "ahb", MXC_CCM_CCGR1, 2, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX3] = imx_clk_gate2_flags("tmax3", "ahb", MXC_CCM_CCGR1, 4, CLK_IS_CRITICAL); + clk[IMX5_CLK_SPBA] = imx_clk_gate2_flags("spba", "ipg", MXC_CCM_CCGR5, 0, CLK_IS_CRITICAL); clk[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2); clk[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3); clk[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3); @@ -252,8 +252,8 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_ECSPI2_PER_GATE] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24); clk[IMX5_CLK_CSPI_IPG_GATE] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26); clk[IMX5_CLK_SDMA_GATE] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30); - clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14); - clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16); + clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2_flags("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14, CLK_IS_CRITICAL); + clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2_flags("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16, CLK_IS_CRITICAL); clk[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); clk[IMX5_CLK_IPU_GATE] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10); clk[IMX5_CLK_NFC_GATE] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20); @@ -267,7 +267,7 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel)); clk[IMX5_CLK_VPU_GATE] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6); clk[IMX5_CLK_VPU_REFERENCE_GATE] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); - clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24); + clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2_flags("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24, CLK_IS_CRITICAL); clk[IMX5_CLK_SSI_APM] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels)); clk[IMX5_CLK_SSI1_ROOT_SEL] = imx_clk_mux("ssi1_root_sel", MXC_CCM_CSCMR1, 14, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); @@ -316,21 +316,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) /* move usb phy clk to 24MHz */ clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]); - - clk_prepare_enable(clk[IMX5_CLK_GPC_DVFS]); - clk_prepare_enable(clk[IMX5_CLK_AHB_MAX]); /* esdhc3 */ - clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ1]); - clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ2]); /* fec */ - clk_prepare_enable(clk[IMX5_CLK_SPBA]); - clk_prepare_enable(clk[IMX5_CLK_EMI_FAST_GATE]); /* fec */ - clk_prepare_enable(clk[IMX5_CLK_EMI_SLOW_GATE]); /* eim */ - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC1_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC2_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_ESC_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSP_GATE]); - clk_prepare_enable(clk[IMX5_CLK_TMAX1]); - clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */ - clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */ } static void __init mx50_clocks_init(struct device_node *np) @@ -442,10 +427,10 @@ static void __init mx51_clocks_init(struct device_node *np) clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0); clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22); - clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6); - clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8); - clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10); - clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12); + clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2_flags("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12, CLK_IS_CRITICAL); clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2, mx51_spdif_xtal_sel, ARRAY_SIZE(mx51_spdif_xtal_sel)); clk[IMX5_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", MXC_CCM_CSCMR2, 2, 2, From d0897bc85ca89d5ddc6c2fcf2f99e04d4a577b63 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 6 Jul 2018 14:08:04 -0700 Subject: [PATCH 39/85] clk: imx51-imx53: Include sizes.h to silence compile errors This driver uses sizes.h, but relies on it being implicitly included somewhere else breaking random direct compilation of the file. Include sizes.h so we can build it those configurations too for better compile coverage. Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx51-imx53.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index 346a53b48f9c..fc8e782d817b 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include From da172d2b6ba8c98101b9c18a986758662a91adbb Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 23 Jun 2018 19:49:25 +0530 Subject: [PATCH 40/85] clk: qcom: Move frequency table macro to common file Frequency table macro is used by multiple clock drivers, move frequency table macro to common header file. Signed-off-by: Taniya Das Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg.h | 2 ++ drivers/clk/qcom/gcc-apq8084.c | 2 -- drivers/clk/qcom/gcc-ipq4019.c | 2 -- drivers/clk/qcom/gcc-ipq8074.c | 2 -- drivers/clk/qcom/gcc-msm8916.c | 2 -- drivers/clk/qcom/gcc-msm8974.c | 2 -- drivers/clk/qcom/gcc-msm8994.c | 2 -- drivers/clk/qcom/gcc-msm8996.c | 2 -- drivers/clk/qcom/gcc-msm8998.c | 2 -- drivers/clk/qcom/gcc-sdm845.c | 2 -- drivers/clk/qcom/mmcc-apq8084.c | 2 -- drivers/clk/qcom/mmcc-msm8974.c | 2 -- drivers/clk/qcom/mmcc-msm8996.c | 2 -- drivers/clk/qcom/videocc-sdm845.c | 2 -- 14 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b209a2fe86b9..dbd5a9e83554 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -7,6 +7,8 @@ #include #include "clk-regmap.h" +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + struct freq_tbl { unsigned long freq; u8 src; diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 486d9610355c..9c99a71ea71e 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -106,8 +106,6 @@ static const char * const gcc_xo_pcie_sleep[] = { "sleep_clk_src", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 46cb256b4aa2..8902ad42ba87 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -179,8 +179,6 @@ static const char * const gcc_xo_ddr_500_200[] = { "ddrpllapss", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = { F(48000000, P_XO, 1, 0, 0), F(200000000, P_FEPLL200, 1, 0, 0), diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 0462f4a8c932..505c6263141d 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -32,8 +32,6 @@ #include "clk-regmap-mux.h" #include "reset.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_XO, P_GPLL0, diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index d6c7f50ba86a..ac2b0aa1e8b5 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -264,8 +264,6 @@ static const char * const gcc_xo_gpll1_emclk_sleep[] = { "sleep_clk", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x21004, .m_reg = 0x21008, diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 348e30da4f18..08e2900d172c 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -62,8 +62,6 @@ static const char * const gcc_xo_gpll0_gpll4[] = { "gpll4_vote", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 1e38efc37180..53f0f369a33e 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -57,8 +57,6 @@ static const char * const gcc_xo_gpll0_gpll4[] = { "gpll4", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_fixed_factor xo = { .mult = 1, .div = 1, diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 9f35b3fe1d97..9d3756cb93bc 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -32,8 +32,6 @@ #include "reset.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_XO, P_GPLL0, diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 78d87f5c7098..9f0ae403d5f5 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -25,8 +25,6 @@ #include "reset.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_AUD_REF_CLK, P_CORE_BI_PLL_TEST_SE, diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index e78e6f5b99fc..19b470fd7b52 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -25,8 +25,6 @@ #include "gdsc.h" #include "reset.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_BI_TCXO, P_AUD_REF_CLK, diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 30777f9f1a43..4ce1d7c88377 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -219,8 +219,6 @@ static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = { "sleep_clk_src", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll mmpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 715e7cd94125..91818516c3e0 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -184,8 +184,6 @@ static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { "dsi1pllbyte", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll mmpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 1a25ee4f3658..60f08b378291 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -34,8 +34,6 @@ #include "reset.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_XO, P_MMPLL0, diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c index 9073b7a710ac..5d6a7724a194 100644 --- a/drivers/clk/qcom/videocc-sdm845.c +++ b/drivers/clk/qcom/videocc-sdm845.c @@ -18,8 +18,6 @@ #include "clk-pll.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_BI_TCXO, P_CORE_BI_PLL_TEST_SE, From 6c79d12e945e85556674a04cde13657a5d7943da Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Sat, 23 Jun 2018 19:49:26 +0530 Subject: [PATCH 41/85] dt-bindings: clock: Introduce QCOM Display clock bindings Add device tree bindings for display clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,dispcc.txt | 19 ++++++++ .../dt-bindings/clock/qcom,dispcc-sdm845.h | 45 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,dispcc.txt create mode 100644 include/dt-bindings/clock/qcom,dispcc-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt new file mode 100644 index 000000000000..d639e18d0b85 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt @@ -0,0 +1,19 @@ +Qualcomm Technologies, Inc. Display Clock Controller Binding +------------------------------------------------------------ + +Required properties : + +- compatible : shall contain "qcom,sdm845-dispcc" +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + dispcc: clock-controller@af00000 { + compatible = "qcom,sdm845-dispcc"; + reg = <0xaf00000 0x100000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h new file mode 100644 index 000000000000..11eed4bc9646 --- /dev/null +++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H +#define _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H + +/* DISP_CC clock registers */ +#define DISP_CC_MDSS_AHB_CLK 0 +#define DISP_CC_MDSS_AXI_CLK 1 +#define DISP_CC_MDSS_BYTE0_CLK 2 +#define DISP_CC_MDSS_BYTE0_CLK_SRC 3 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 4 +#define DISP_CC_MDSS_BYTE1_CLK 5 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 6 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 7 +#define DISP_CC_MDSS_ESC0_CLK 8 +#define DISP_CC_MDSS_ESC0_CLK_SRC 9 +#define DISP_CC_MDSS_ESC1_CLK 10 +#define DISP_CC_MDSS_ESC1_CLK_SRC 11 +#define DISP_CC_MDSS_MDP_CLK 12 +#define DISP_CC_MDSS_MDP_CLK_SRC 13 +#define DISP_CC_MDSS_MDP_LUT_CLK 14 +#define DISP_CC_MDSS_PCLK0_CLK 15 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 16 +#define DISP_CC_MDSS_PCLK1_CLK 17 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 18 +#define DISP_CC_MDSS_ROT_CLK 19 +#define DISP_CC_MDSS_ROT_CLK_SRC 20 +#define DISP_CC_MDSS_RSCC_AHB_CLK 21 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 22 +#define DISP_CC_MDSS_VSYNC_CLK 23 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 24 +#define DISP_CC_PLL0 25 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 26 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 27 + +/* DISP_CC Reset */ +#define DISP_CC_MDSS_RSCC_BCR 0 + +/* DISP_CC GDSCR */ +#define MDSS_GDSC 0 + +#endif From a64ad008980c65d38e6cf6858429c78e6b740c41 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Fri, 6 Jul 2018 15:18:51 +0200 Subject: [PATCH 42/85] clk: rockchip: fix clk_i2sout parent selection bits on rk3399 Register, shift and mask were wrong according to datasheet. Fixes: 115510053e5e ("clk: rockchip: add clock controller for the RK3399") Cc: stable@vger.kernel.org Signed-off-by: Alberto Panizzo Signed-off-by: Anthony Brandon Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3399.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index bca10d618f0a..2a8634a52856 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -631,7 +631,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(31), 0, 2, MFLAGS), COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT, - RK3399_CLKSEL_CON(30), 8, 2, MFLAGS, + RK3399_CLKSEL_CON(31), 2, 1, MFLAGS, RK3399_CLKGATE_CON(8), 12, GFLAGS), /* uart */ From f7b3182232c82bb9769e2d5471d702bae2972d2b Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 29 Jun 2018 17:38:14 +0300 Subject: [PATCH 43/85] clk: tegra: bpmp: Don't crash when a clock fails to register When registering clocks, we just skip any that fail to register (leaving a NULL hole in the clock table). However, our of_xlate function still tries to dereference each entry while looking for the clock with the requested id, causing a crash if any clocks failed to register. Add a check to of_xlate to skip any NULL clocks. Signed-off-by: Mikko Perttunen Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-bpmp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index a896692b74ec..01dada561c10 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -586,9 +586,15 @@ static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec, unsigned int id = clkspec->args[0], i; struct tegra_bpmp *bpmp = data; - for (i = 0; i < bpmp->num_clocks; i++) - if (bpmp->clocks[i]->id == id) - return &bpmp->clocks[i]->hw; + for (i = 0; i < bpmp->num_clocks; i++) { + struct tegra_bpmp_clk *clk = bpmp->clocks[i]; + + if (!clk) + continue; + + if (clk->id == id) + return &clk->hw; + } return NULL; } From 26f8590c4a1f7bd30ef9b9d713388bd96eb43d16 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 11 Jun 2018 10:18:53 +0200 Subject: [PATCH 44/85] clk: tegra: Make vic03 a child of pll_c3 By default, the vic03 clock is a child of pll_m but that runs at 924 MHz which is too fast for VIC. Make vic03 a child of pll_c3 by default so it will run at a supported frequency. Signed-off-by: Thierry Reding Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra124.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 0c69c7970950..f5048f82c0b9 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1290,6 +1290,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1 }, { TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1 }, { TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0 }, + { TEGRA124_CLK_VIC03, TEGRA124_CLK_PLL_C3, 0, 0 }, /* must be the last entry */ { TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 }, }; From 8097d4c75f00f3fce8f4916521ec61ec0c607324 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 11 Jun 2018 10:20:37 +0200 Subject: [PATCH 45/85] clk: tegra: Make vde a child of pll_c3 The current default is to leave the VDE clock's parent at the default, which is clk_m. However, that is not a configuration that will allow the VDE to function. Reparent it to pll_c3 instead to make sure the hardware can actually decode video content. Signed-off-by: Thierry Reding Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra124.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index f5048f82c0b9..b6cf28ca2ed2 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1267,7 +1267,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, - { TEGRA124_CLK_VDE, TEGRA124_CLK_CLK_MAX, 600000000, 0 }, + { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_C3, 600000000, 0 }, { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, From da0d2239a56ec8fe6a617aade5901ab3bffc1ef4 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 4 Jun 2018 01:48:05 +0300 Subject: [PATCH 46/85] clk: tegra: Mark Memory Controller clock as critical Memory Controller should be always-on. Currently the sibling EMC clock is marked as critical, let's mark MC clock too for consistency. Signed-off-by: Dmitry Osipenko Acked-By: Peter De Schrijver Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-divider.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 16e0aee14773..58874c1bbf5e 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -194,6 +194,7 @@ static const struct clk_div_table mc_div_table[] = { struct clk *tegra_clk_register_mc(const char *name, const char *parent_name, void __iomem *reg, spinlock_t *lock) { - return clk_register_divider_table(NULL, name, parent_name, 0, reg, - 16, 1, 0, mc_div_table, lock); + return clk_register_divider_table(NULL, name, parent_name, + CLK_IS_CRITICAL, reg, 16, 1, 0, + mc_div_table, lock); } From 405fcacbd866cfe75733b94bacdef5bcb4aa6c6c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 5 Jun 2018 15:12:32 +0300 Subject: [PATCH 47/85] clk: tegra: emc: Avoid out-of-bounds bug Apparently there was an attempt to avoid out-of-bounds accesses when there is only one memory timing available, but there is a typo in the code that neglects that attempt. Signed-off-by: Dmitry Osipenko Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-emc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 5234acd30e89..0621a3a82ea6 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -132,7 +132,7 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) timing = tegra->timings + i; if (timing->rate > req->max_rate) { - i = min(i, 1); + i = max(i, 1); req->rate = tegra->timings[i - 1].rate; return 0; } From de3c1e71d412d7e254e3eebeb82e260fb8513566 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 4 Jul 2018 18:54:57 +0200 Subject: [PATCH 48/85] clk: meson: expose GEN_CLK clkid Expose GEN_CLK clock id Signed-off-by: Jerome Brunet --- include/dt-bindings/clock/axg-clkc.h | 1 + include/dt-bindings/clock/gxbb-clkc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h index 70371228b7e0..fd1f938c38d1 100644 --- a/include/dt-bindings/clock/axg-clkc.h +++ b/include/dt-bindings/clock/axg-clkc.h @@ -71,5 +71,6 @@ #define CLKID_PCIE_CML_EN0 79 #define CLKID_PCIE_CML_EN1 80 #define CLKID_MIPI_ENABLE 81 +#define CLKID_GEN_CLK 84 #endif /* __AXG_CLKC_H */ diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index 7a892be90549..3979d48c025f 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -127,5 +127,6 @@ #define CLKID_VAPB 140 #define CLKID_VDEC_1 153 #define CLKID_VDEC_HEVC 156 +#define CLKID_GEN_CLK 159 #endif /* __GXBB_CLKC_H */ From 60e267f3fd73366feac2c0be5a50feb24118c2ca Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 19 Jun 2018 18:00:50 +0200 Subject: [PATCH 49/85] clk: meson: remove obsolete register access The legacy method to access the hhi register space is not longer used. We can safely drop it now. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 37 ++----------------------------------- drivers/clk/meson/gxbb.c | 36 ++---------------------------------- 2 files changed, 4 insertions(+), 69 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index bd4dbc696b88..3fb884db1b10 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -995,49 +994,17 @@ static const struct of_device_id clkc_match_table[] = { {} }; -static const struct regmap_config clkc_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, -}; - static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; - void __iomem *clk_base = NULL; struct regmap *map; int ret, i; /* Get the hhi system controller node if available */ map = syscon_node_to_regmap(of_get_parent(dev->of_node)); if (IS_ERR(map)) { - dev_err(dev, - "failed to get HHI regmap - Trying obsolete regs\n"); - - /* - * FIXME: HHI registers should be accessed through - * the appropriate system controller. This is required because - * there is more than just clocks in this register space - * - * This fallback method is only provided temporarily until - * all the platform DTs are properly using the syscon node - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - - clk_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!clk_base) { - dev_err(dev, "Unable to map clk base\n"); - return -ENXIO; - } - - map = devm_regmap_init_mmio(dev, clk_base, - &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); + dev_err(dev, "failed to get HHI regmap\n"); + return PTR_ERR(map); } /* Populate regmap for the regmap backed clocks */ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 177fffb9ebef..297ebc391475 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -2228,17 +2227,9 @@ static const struct of_device_id clkc_match_table[] = { {}, }; -static const struct regmap_config clkc_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, -}; - static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; - struct resource *res; - void __iomem *clk_base; struct regmap *map; int ret, i; struct device *dev = &pdev->dev; @@ -2250,31 +2241,8 @@ static int gxbb_clkc_probe(struct platform_device *pdev) /* Get the hhi system controller node if available */ map = syscon_node_to_regmap(of_get_parent(dev->of_node)); if (IS_ERR(map)) { - dev_err(dev, - "failed to get HHI regmap - Trying obsolete regs\n"); - - /* - * FIXME: HHI registers should be accessed through - * the appropriate system controller. This is required because - * there is more than just clocks in this register space - * - * This fallback method is only provided temporarily until - * all the platform DTs are properly using the syscon node - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - clk_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!clk_base) { - dev_err(dev, "Unable to map clk base\n"); - return -ENXIO; - } - - map = devm_regmap_init_mmio(dev, clk_base, - &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); + dev_err(dev, "failed to get HHI regmap\n"); + return PTR_ERR(map); } /* Populate regmap for the common regmap backed clocks */ From 443f2285789d2a4bf616b610c4cd8db839660a4a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:52 +0200 Subject: [PATCH 50/85] clk: meson: clean-up meson clock configuration Clean the dependencies in meson clock Kconfig. CLK_AMLOGIC should actually select CLK_REGMAP_MESON which it uses. Also, each platform should select CLK_AMLOGIC, so everything is properly turned on when the platform Kconfig enable each configuration flag Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 815659eebea3..9d00809f07fc 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -1,13 +1,14 @@ config COMMON_CLK_AMLOGIC bool - depends on OF depends on ARCH_MESON || COMPILE_TEST + select COMMON_CLK_REGMAP_MESON config COMMON_CLK_MESON_AO bool depends on OF depends on ARCH_MESON || COMPILE_TEST select COMMON_CLK_REGMAP_MESON + select RESET_CONTROLLER config COMMON_CLK_REGMAP_MESON bool @@ -15,9 +16,8 @@ config COMMON_CLK_REGMAP_MESON config COMMON_CLK_MESON8B bool - depends on COMMON_CLK_AMLOGIC + select COMMON_CLK_AMLOGIC select RESET_CONTROLLER - select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you @@ -25,10 +25,8 @@ config COMMON_CLK_MESON8B config COMMON_CLK_GXBB bool - depends on COMMON_CLK_AMLOGIC - select RESET_CONTROLLER + select COMMON_CLK_AMLOGIC select COMMON_CLK_MESON_AO - select COMMON_CLK_REGMAP_MESON select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. @@ -36,10 +34,8 @@ config COMMON_CLK_GXBB config COMMON_CLK_AXG bool - depends on COMMON_CLK_AMLOGIC - select RESET_CONTROLLER + select COMMON_CLK_AMLOGIC select COMMON_CLK_MESON_AO - select COMMON_CLK_REGMAP_MESON select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. From 47f21315a6e4454ed9d8a450288a0989113e1e44 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:53 +0200 Subject: [PATCH 51/85] clk: meson: add clk-phase clock driver Add a driver based meson clk-regmap to control clock phase on amlogic SoCs Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Makefile | 1 + drivers/clk/meson/clk-phase.c | 63 +++++++++++++++++++++++++++++++++++ drivers/clk/meson/clkc.h | 8 +++++ 3 files changed, 72 insertions(+) create mode 100644 drivers/clk/meson/clk-phase.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index d0d13aeb369a..162e4a6f5c55 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c new file mode 100644 index 000000000000..cba43748ce3d --- /dev/null +++ b/drivers/clk/meson/clk-phase.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include "clkc.h" + +#define phase_step(_width) (360 / (1 << (_width))) + +static inline struct meson_clk_phase_data * +meson_clk_phase_data(struct clk_regmap *clk) +{ + return (struct meson_clk_phase_data *)clk->data; +} + +int meson_clk_degrees_from_val(unsigned int val, unsigned int width) +{ + return phase_step(width) * val; +} +EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val); + +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) +{ + unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width)); + + /* + * This last calculation is here for cases when degrees is rounded + * to 360, in which case val == (1 << width). + */ + return val % (1 << width); +} +EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val); + +static int meson_clk_phase_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); + unsigned int val; + + val = meson_parm_read(clk->map, &phase->ph); + + return meson_clk_degrees_from_val(val, phase->ph.width); +} + +static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, phase->ph.width); + meson_parm_write(clk->map, &phase->ph, val); + + return 0; +} + +const struct clk_ops meson_clk_phase_ops = { + .get_phase = meson_clk_phase_get_phase, + .set_phase = meson_clk_phase_set_phase, +}; +EXPORT_SYMBOL_GPL(meson_clk_phase_ops); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 2fb084330ee9..fd520ccdd1be 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -96,6 +96,13 @@ struct meson_clk_audio_div_data { u8 flags; }; +struct meson_clk_phase_data { + struct parm ph; +}; + +int meson_clk_degrees_from_val(unsigned int val, unsigned int width); +unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width); + #define MESON_GATE(_name, _reg, _bit) \ struct clk_regmap _name = { \ .data = &(struct clk_regmap_gate_data){ \ @@ -119,5 +126,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops; extern const struct clk_ops meson_clk_mpll_ops; extern const struct clk_ops meson_clk_audio_divider_ro_ops; extern const struct clk_ops meson_clk_audio_divider_ops; +extern const struct clk_ops meson_clk_phase_ops; #endif /* __CLKC_H */ From e8dd9207763e0317ac256c78dcd50dca7826f2f6 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:54 +0200 Subject: [PATCH 52/85] clk: meson: add triple phase clock driver Add a driver to control the output of the sample clock generator found in the axg audio clock controller. The goal of this driver is to coherently control the phase provided to the different element using the sample clock generator. This simplify the usage of the sample clock generator a lot, without comprising the ability of the SoC. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 5 +++ drivers/clk/meson/Makefile | 1 + drivers/clk/meson/clk-triphase.c | 68 ++++++++++++++++++++++++++++++++ drivers/clk/meson/clkc-audio.h | 20 ++++++++++ 4 files changed, 94 insertions(+) create mode 100644 drivers/clk/meson/clk-triphase.c create mode 100644 drivers/clk/meson/clkc-audio.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 9d00809f07fc..9ad95966aa3d 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -3,6 +3,11 @@ config COMMON_CLK_AMLOGIC depends on ARCH_MESON || COMPILE_TEST select COMMON_CLK_REGMAP_MESON +config COMMON_CLK_AMLOGIC_AUDIO + bool + depends on ARCH_MESON || COMPILE_TEST + select COMMON_CLK_AMLOGIC + config COMMON_CLK_MESON_AO bool depends on OF diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 162e4a6f5c55..74ec070b0974 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c new file mode 100644 index 000000000000..4a59936251e5 --- /dev/null +++ b/drivers/clk/meson/clk-triphase.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include "clkc-audio.h" + +/* + * This is a special clock for the audio controller. + * The phase of mst_sclk clock output can be controlled independently + * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2). + * Controlling these 3 phases as just one makes things simpler and + * give the same clock view to all the element on the i2s bus. + * If necessary, we can still control the phase in the tdm block + * which makes these independent control redundant. + */ +static inline struct meson_clk_triphase_data * +meson_clk_triphase_data(struct clk_regmap *clk) +{ + return (struct meson_clk_triphase_data *)clk->data; +} + +static void meson_clk_triphase_sync(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + /* Get phase 0 and sync it to phase 1 and 2 */ + val = meson_parm_read(clk->map, &tph->ph0); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); +} + +static int meson_clk_triphase_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + /* Phase are in sync, reading phase 0 is enough */ + val = meson_parm_read(clk->map, &tph->ph0); + + return meson_clk_degrees_from_val(val, tph->ph0.width); +} + +static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, tph->ph0.width); + meson_parm_write(clk->map, &tph->ph0, val); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); + + return 0; +} + +const struct clk_ops meson_clk_triphase_ops = { + .init = meson_clk_triphase_sync, + .get_phase = meson_clk_triphase_get_phase, + .set_phase = meson_clk_triphase_set_phase, +}; +EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h new file mode 100644 index 000000000000..286ff1201258 --- /dev/null +++ b/drivers/clk/meson/clkc-audio.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLKC_AUDIO_H +#define __MESON_CLKC_AUDIO_H + +#include "clkc.h" + +struct meson_clk_triphase_data { + struct parm ph0; + struct parm ph1; + struct parm ph2; +}; + +extern const struct clk_ops meson_clk_triphase_ops; + +#endif /* __MESON_CLKC_AUDIO_H */ From 3054a55c5dd2619a597d6e96d8589318f2b210ad Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:55 +0200 Subject: [PATCH 53/85] clk: meson: add axg audio sclk divider driver Add a driver to control the clock divider found in the sample clock generator of the axg audio clock controller. The sclk divider accumulates specific features which make the generic divider unsuitable to control it: - zero based divider (div = val + 1), but zero value gates the clock, so minimum divider value is 2. - lrclk variant may adjust the duty cycle depending the divider value and the 'hi' value. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/clkc-audio.h | 8 ++ drivers/clk/meson/sclk-div.c | 243 +++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/meson/sclk-div.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 74ec070b0974..1574e3f0de5c 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o -obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h index 286ff1201258..0a7c157ebf81 100644 --- a/drivers/clk/meson/clkc-audio.h +++ b/drivers/clk/meson/clkc-audio.h @@ -15,6 +15,14 @@ struct meson_clk_triphase_data { struct parm ph2; }; +struct meson_sclk_div_data { + struct parm div; + struct parm hi; + unsigned int cached_div; + struct clk_duty cached_duty; +}; + extern const struct clk_ops meson_clk_triphase_ops; +extern const struct clk_ops meson_sclk_div_ops; #endif /* __MESON_CLKC_AUDIO_H */ diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c new file mode 100644 index 000000000000..bc64019b8eeb --- /dev/null +++ b/drivers/clk/meson/sclk-div.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + * + * Sample clock generator divider: + * This HW divider gates with value 0 but is otherwise a zero based divider: + * + * val >= 1 + * divider = val + 1 + * + * The duty cycle may also be set for the LR clock variant. The duty cycle + * ratio is: + * + * hi = [0 - val] + * duty_cycle = (1 + hi) / (1 + val) + */ + +#include "clkc-audio.h" + +static inline struct meson_sclk_div_data * +meson_sclk_div_data(struct clk_regmap *clk) +{ + return (struct meson_sclk_div_data *)clk->data; +} + +static int sclk_div_maxval(struct meson_sclk_div_data *sclk) +{ + return (1 << sclk->div.width) - 1; +} + +static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk) +{ + return sclk_div_maxval(sclk) + 1; +} + +static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate, + unsigned long prate, int maxdiv) +{ + int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate); + + return clamp(div, 2, maxdiv); +} + +static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *prate, + struct meson_sclk_div_data *sclk) +{ + struct clk_hw *parent = clk_hw_get_parent(hw); + int bestdiv = 0, i; + unsigned long maxdiv, now, parent_now; + unsigned long best = 0, best_parent = 0; + + if (!rate) + rate = 1; + + maxdiv = sclk_div_maxdiv(sclk); + + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) + return sclk_div_getdiv(hw, rate, *prate, maxdiv); + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 2; i <= maxdiv; i++) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + if (rate * i == *prate) + return i; + + parent_now = clk_hw_round_rate(parent, rate * i); + now = DIV_ROUND_UP_ULL((u64)parent_now, i); + + if (abs(rate - now) < abs(rate - best)) { + bestdiv = i; + best = now; + best_parent = parent_now; + } + } + + if (!bestdiv) + bestdiv = sclk_div_maxdiv(sclk); + else + *prate = best_parent; + + return bestdiv; +} + +static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + int div; + + div = sclk_div_bestdiv(hw, rate, prate, sclk); + + return DIV_ROUND_UP_ULL((u64)*prate, div); +} + +static void sclk_apply_ratio(struct clk_regmap *clk, + struct meson_sclk_div_data *sclk) +{ + unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div * + sclk->cached_duty.num, + sclk->cached_duty.den); + + if (hi) + hi -= 1; + + meson_parm_write(clk->map, &sclk->hi, hi); +} + +static int sclk_div_set_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + if (MESON_PARM_APPLICABLE(&sclk->hi)) { + memcpy(&sclk->cached_duty, duty, sizeof(*duty)); + sclk_apply_ratio(clk, sclk); + } + + return 0; +} + +static int sclk_div_get_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + int hi; + + if (!MESON_PARM_APPLICABLE(&sclk->hi)) { + duty->num = 1; + duty->den = 2; + return 0; + } + + hi = meson_parm_read(clk->map, &sclk->hi); + duty->num = hi + 1; + duty->den = sclk->cached_div; + return 0; +} + +static void sclk_apply_divider(struct clk_regmap *clk, + struct meson_sclk_div_data *sclk) +{ + if (MESON_PARM_APPLICABLE(&sclk->hi)) + sclk_apply_ratio(clk, sclk); + + meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1); +} + +static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + unsigned long maxdiv = sclk_div_maxdiv(sclk); + + sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv); + + if (clk_hw_is_enabled(hw)) + sclk_apply_divider(clk, sclk); + + return 0; +} + +static unsigned long sclk_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div); +} + +static int sclk_div_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + sclk_apply_divider(clk, sclk); + + return 0; +} + +static void sclk_div_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + meson_parm_write(clk->map, &sclk->div, 0); +} + +static int sclk_div_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + + if (meson_parm_read(clk->map, &sclk->div)) + return 1; + + return 0; +} + +static void sclk_div_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + unsigned int val; + + val = meson_parm_read(clk->map, &sclk->div); + + /* if the divider is initially disabled, assume max */ + if (!val) + sclk->cached_div = sclk_div_maxdiv(sclk); + else + sclk->cached_div = val + 1; + + sclk_div_get_duty_cycle(hw, &sclk->cached_duty); +} + +const struct clk_ops meson_sclk_div_ops = { + .recalc_rate = sclk_div_recalc_rate, + .round_rate = sclk_div_round_rate, + .set_rate = sclk_div_set_rate, + .enable = sclk_div_enable, + .disable = sclk_div_disable, + .is_enabled = sclk_div_is_enabled, + .get_duty_cycle = sclk_div_get_duty_cycle, + .set_duty_cycle = sclk_div_set_duty_cycle, + .init = sclk_div_init, +}; +EXPORT_SYMBOL_GPL(meson_sclk_div_ops); From 1cd50181750f4bde1e4305812a8df5a5731ed28a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 22 May 2018 18:34:57 +0200 Subject: [PATCH 54/85] clk: meson: axg: add the audio clock controller driver The axg audio clock controller is the clock generation unit for the amlogic audio subsystem of A113 based SoCs. It may be clocked by 8 different plls provided by the primary clock controller and also by 10 slave bit clocks and 10 slave sample clocks which may be provided by external components, such as audio codecs, through the SoC pads. It contains several muxes, dividers and gates which are fed into the the different devices of the audio subsystem. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 9 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/axg-audio.c | 845 ++++++++++++++++++++++++++++++++++ drivers/clk/meson/axg-audio.h | 127 +++++ 4 files changed, 982 insertions(+) create mode 100644 drivers/clk/meson/axg-audio.c create mode 100644 drivers/clk/meson/axg-audio.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 9ad95966aa3d..efaa70f682b4 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -45,3 +45,12 @@ config COMMON_CLK_AXG help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. + +config COMMON_CLK_AXG_AUDIO + tristate "Meson AXG Audio Clock Controller Driver" + depends on COMMON_CLK_AXG + select COMMON_CLK_AMLOGIC_AUDIO + select MFD_SYSCON + help + Support for the audio clock controller on AmLogic A113D devices, + aka axg, Say Y if you want audio subsystem to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 1574e3f0de5c..fd97f5ba317d 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o +obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c new file mode 100644 index 000000000000..a0ed41e73bde --- /dev/null +++ b/drivers/clk/meson/axg-audio.c @@ -0,0 +1,845 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clkc-audio.h" +#include "axg-audio.h" + +#define AXG_MST_IN_COUNT 8 +#define AXG_SLV_SCLK_COUNT 10 +#define AXG_SLV_LRCLK_COUNT 10 + +#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ +struct clk_regmap axg_##_name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "axg_"#_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ _pname }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ +struct clk_regmap axg_##_name = { \ + .data = &(struct clk_regmap_mux_data){ \ + .offset = (_reg), \ + .mask = (_mask), \ + .shift = (_shift), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = "axg_"#_name, \ + .ops = &clk_regmap_mux_ops, \ + .parent_names = (_pnames), \ + .num_parents = ARRAY_SIZE(_pnames), \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ +struct clk_regmap axg_##_name = { \ + .data = &(struct clk_regmap_div_data){ \ + .offset = (_reg), \ + .shift = (_shift), \ + .width = (_width), \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ + .name = "axg_"#_name, \ + .ops = &clk_regmap_divider_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define AXG_PCLK_GATE(_name, _bit) \ + AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0) + +/* Audio peripheral clocks */ +static AXG_PCLK_GATE(ddr_arb, 0); +static AXG_PCLK_GATE(pdm, 1); +static AXG_PCLK_GATE(tdmin_a, 2); +static AXG_PCLK_GATE(tdmin_b, 3); +static AXG_PCLK_GATE(tdmin_c, 4); +static AXG_PCLK_GATE(tdmin_lb, 5); +static AXG_PCLK_GATE(tdmout_a, 6); +static AXG_PCLK_GATE(tdmout_b, 7); +static AXG_PCLK_GATE(tdmout_c, 8); +static AXG_PCLK_GATE(frddr_a, 9); +static AXG_PCLK_GATE(frddr_b, 10); +static AXG_PCLK_GATE(frddr_c, 11); +static AXG_PCLK_GATE(toddr_a, 12); +static AXG_PCLK_GATE(toddr_b, 13); +static AXG_PCLK_GATE(toddr_c, 14); +static AXG_PCLK_GATE(loopback, 15); +static AXG_PCLK_GATE(spdifin, 16); +static AXG_PCLK_GATE(spdifout, 17); +static AXG_PCLK_GATE(resample, 18); +static AXG_PCLK_GATE(power_detect, 19); + +/* Audio Master Clocks */ +static const char * const mst_mux_parent_names[] = { + "axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3", + "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", +}; + +#define AXG_MST_MCLK_MUX(_name, _reg) \ + AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \ + mst_mux_parent_names, CLK_SET_RATE_PARENT) + +static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + +#define AXG_MST_MCLK_DIV(_name, _reg) \ + AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \ + "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ + +static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + +#define AXG_MST_MCLK_GATE(_name, _reg) \ + AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ + CLK_SET_RATE_PARENT) + +static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); +static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); +static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); +static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); +static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); +static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); +static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + +/* Sample Clocks */ +#define AXG_MST_SCLK_PRE_EN(_name, _reg) \ + AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ + "axg_mst_"#_name"_mclk", 0) + +static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ + _hi_shift, _hi_width, _pname, _iflags) \ +struct clk_regmap axg_##_name = { \ + .data = &(struct meson_sclk_div_data) { \ + .div = { \ + .reg_off = (_reg), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + }, \ + .hi = { \ + .reg_off = (_reg), \ + .shift = (_hi_shift), \ + .width = (_hi_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "axg_"#_name, \ + .ops = &meson_sclk_div_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ + .flags = (_iflags), \ + }, \ +} + +#define AXG_MST_SCLK_DIV(_name, _reg) \ + AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ + "axg_mst_"#_name"_sclk_pre_en", \ + CLK_SET_RATE_PARENT) + +static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AXG_MST_SCLK_POST_EN(_name, _reg) \ + AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ + "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) + +static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); +static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); +static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); +static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); +static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); +static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ + _pname, _iflags) \ +struct clk_regmap axg_##_name = { \ + .data = &(struct meson_clk_triphase_data) { \ + .ph0 = { \ + .reg_off = (_reg), \ + .shift = (_shift0), \ + .width = (_width), \ + }, \ + .ph1 = { \ + .reg_off = (_reg), \ + .shift = (_shift1), \ + .width = (_width), \ + }, \ + .ph2 = { \ + .reg_off = (_reg), \ + .shift = (_shift2), \ + .width = (_width), \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "axg_"#_name, \ + .ops = &meson_clk_triphase_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ + }, \ +} + +#define AXG_MST_SCLK(_name, _reg) \ + AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ + "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) + +static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +#define AXG_MST_LRCLK_DIV(_name, _reg) \ + AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ + "axg_mst_"#_name"_sclk_post_en", 0) \ + +static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); + +#define AXG_MST_LRCLK(_name, _reg) \ + AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ + "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) + +static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); +static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); +static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); +static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); +static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); +static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); + +static const char * const tdm_sclk_parent_names[] = { + "axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk", + "axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk", + "axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2", + "axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5", + "axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8", + "axg_slv_sclk9" +}; + +#define AXG_TDM_SCLK_MUX(_name, _reg) \ + AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ + CLK_MUX_ROUND_CLOSEST, \ + tdm_sclk_parent_names, 0) + +static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AXG_TDM_SCLK_PRE_EN(_name, _reg) \ + AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ + "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) + +static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AXG_TDM_SCLK_POST_EN(_name, _reg) \ + AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ + "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) + +static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +#define AXG_TDM_SCLK(_name, _reg) \ + struct clk_regmap axg_tdm##_name##_sclk = { \ + .data = &(struct meson_clk_phase_data) { \ + .ph = { \ + .reg_off = (_reg), \ + .shift = 29, \ + .width = 1, \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "axg_tdm"#_name"_sclk", \ + .ops = &meson_clk_phase_ops, \ + .parent_names = (const char *[]) \ + { "axg_tdm"#_name"_sclk_post_en" }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ + }, \ +} + +static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +static const char * const tdm_lrclk_parent_names[] = { + "axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk", + "axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk", + "axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2", + "axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5", + "axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8", + "axg_slv_lrclk9" +}; + +#define AXG_TDM_LRLCK(_name, _reg) \ + AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ + CLK_MUX_ROUND_CLOSEST, \ + tdm_lrclk_parent_names, 0) + +static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + +/* + * Array of all clocks provided by this provider + * The input clocks of the controller will be populated at runtime + */ +static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { + .hws = { + [AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw, + [AUD_CLKID_PDM] = &axg_pdm.hw, + [AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw, + [AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw, + [AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw, + [AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw, + [AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw, + [AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw, + [AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw, + [AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw, + [AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw, + [AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw, + [AUD_CLKID_TODDR_A] = &axg_toddr_a.hw, + [AUD_CLKID_TODDR_B] = &axg_toddr_b.hw, + [AUD_CLKID_TODDR_C] = &axg_toddr_c.hw, + [AUD_CLKID_LOOPBACK] = &axg_loopback.hw, + [AUD_CLKID_SPDIFIN] = &axg_spdifin.hw, + [AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw, + [AUD_CLKID_RESAMPLE] = &axg_resample.hw, + [AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw, + [AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw, + [AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw, + [AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw, + [AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw, + [AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw, + [AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw, + [AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw, + [AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw, + [AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw, + [AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw, + [AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw, + [AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw, + [AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw, + [AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw, + [AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw, + [AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw, + [AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw, + [AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw, + [AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw, + [AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw, + [AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw, + [AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw, + [AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw, + [AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw, + [AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw, + [AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw, + [AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw, + [AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw, + [AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw, + [AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw, + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw, + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw, + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw, + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw, + [AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw, + [AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw, + [AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw, + [AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw, + [AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw, + [AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw, + [AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw, + [AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw, + [AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw, + [AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw, + [AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw, + [AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw, + [AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw, + [AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw, + [AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw, + [AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw, + [AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw, + [AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw, + [AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw, + [AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw, + [AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw, + [AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw, + [AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw, + [AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw, + [AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw, + [AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw, + [AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw, + [AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw, + [AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw, + [AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw, + [AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw, + [AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw, + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw, + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw, + [AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw, + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw, + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw, + [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw, + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw, + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw, + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw, + [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw, + [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw, + [AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw, + [AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw, + [AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw, + [AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw, + [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, + [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, + [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, + [AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw, + [AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw, + [AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw, + [AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw, + [AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw, + [AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw, + [AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +}; + +/* Convenience table to populate regmap in .probe() */ +static struct clk_regmap *const axg_audio_clk_regmaps[] = { + &axg_ddr_arb, + &axg_pdm, + &axg_tdmin_a, + &axg_tdmin_b, + &axg_tdmin_c, + &axg_tdmin_lb, + &axg_tdmout_a, + &axg_tdmout_b, + &axg_tdmout_c, + &axg_frddr_a, + &axg_frddr_b, + &axg_frddr_c, + &axg_toddr_a, + &axg_toddr_b, + &axg_toddr_c, + &axg_loopback, + &axg_spdifin, + &axg_spdifout, + &axg_resample, + &axg_power_detect, + &axg_mst_a_mclk_sel, + &axg_mst_b_mclk_sel, + &axg_mst_c_mclk_sel, + &axg_mst_d_mclk_sel, + &axg_mst_e_mclk_sel, + &axg_mst_f_mclk_sel, + &axg_mst_a_mclk_div, + &axg_mst_b_mclk_div, + &axg_mst_c_mclk_div, + &axg_mst_d_mclk_div, + &axg_mst_e_mclk_div, + &axg_mst_f_mclk_div, + &axg_mst_a_mclk, + &axg_mst_b_mclk, + &axg_mst_c_mclk, + &axg_mst_d_mclk, + &axg_mst_e_mclk, + &axg_mst_f_mclk, + &axg_spdifout_clk_sel, + &axg_spdifout_clk_div, + &axg_spdifout_clk, + &axg_spdifin_clk_sel, + &axg_spdifin_clk_div, + &axg_spdifin_clk, + &axg_pdm_dclk_sel, + &axg_pdm_dclk_div, + &axg_pdm_dclk, + &axg_pdm_sysclk_sel, + &axg_pdm_sysclk_div, + &axg_pdm_sysclk, + &axg_mst_a_sclk_pre_en, + &axg_mst_b_sclk_pre_en, + &axg_mst_c_sclk_pre_en, + &axg_mst_d_sclk_pre_en, + &axg_mst_e_sclk_pre_en, + &axg_mst_f_sclk_pre_en, + &axg_mst_a_sclk_div, + &axg_mst_b_sclk_div, + &axg_mst_c_sclk_div, + &axg_mst_d_sclk_div, + &axg_mst_e_sclk_div, + &axg_mst_f_sclk_div, + &axg_mst_a_sclk_post_en, + &axg_mst_b_sclk_post_en, + &axg_mst_c_sclk_post_en, + &axg_mst_d_sclk_post_en, + &axg_mst_e_sclk_post_en, + &axg_mst_f_sclk_post_en, + &axg_mst_a_sclk, + &axg_mst_b_sclk, + &axg_mst_c_sclk, + &axg_mst_d_sclk, + &axg_mst_e_sclk, + &axg_mst_f_sclk, + &axg_mst_a_lrclk_div, + &axg_mst_b_lrclk_div, + &axg_mst_c_lrclk_div, + &axg_mst_d_lrclk_div, + &axg_mst_e_lrclk_div, + &axg_mst_f_lrclk_div, + &axg_mst_a_lrclk, + &axg_mst_b_lrclk, + &axg_mst_c_lrclk, + &axg_mst_d_lrclk, + &axg_mst_e_lrclk, + &axg_mst_f_lrclk, + &axg_tdmin_a_sclk_sel, + &axg_tdmin_b_sclk_sel, + &axg_tdmin_c_sclk_sel, + &axg_tdmin_lb_sclk_sel, + &axg_tdmout_a_sclk_sel, + &axg_tdmout_b_sclk_sel, + &axg_tdmout_c_sclk_sel, + &axg_tdmin_a_sclk_pre_en, + &axg_tdmin_b_sclk_pre_en, + &axg_tdmin_c_sclk_pre_en, + &axg_tdmin_lb_sclk_pre_en, + &axg_tdmout_a_sclk_pre_en, + &axg_tdmout_b_sclk_pre_en, + &axg_tdmout_c_sclk_pre_en, + &axg_tdmin_a_sclk_post_en, + &axg_tdmin_b_sclk_post_en, + &axg_tdmin_c_sclk_post_en, + &axg_tdmin_lb_sclk_post_en, + &axg_tdmout_a_sclk_post_en, + &axg_tdmout_b_sclk_post_en, + &axg_tdmout_c_sclk_post_en, + &axg_tdmin_a_sclk, + &axg_tdmin_b_sclk, + &axg_tdmin_c_sclk, + &axg_tdmin_lb_sclk, + &axg_tdmout_a_sclk, + &axg_tdmout_b_sclk, + &axg_tdmout_c_sclk, + &axg_tdmin_a_lrclk, + &axg_tdmin_b_lrclk, + &axg_tdmin_c_lrclk, + &axg_tdmin_lb_lrclk, + &axg_tdmout_a_lrclk, + &axg_tdmout_b_lrclk, + &axg_tdmout_c_lrclk, +}; + +static struct clk *devm_clk_get_enable(struct device *dev, char *id) +{ + struct clk *clk; + int ret; + + clk = devm_clk_get(dev, id); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "failed to get %s", id); + return clk; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "failed to enable %s", id); + return ERR_PTR(ret); + } + + ret = devm_add_action_or_reset(dev, + (void(*)(void *))clk_disable_unprepare, + clk); + if (ret) { + dev_err(dev, "failed to add reset action on %s", id); + return ERR_PTR(ret); + } + + return clk; +} + +static const struct clk_ops axg_clk_no_ops = {}; + +static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev, + const char *name, + const char *parent_name) +{ + struct clk_hw *hw; + struct clk_init_data init; + char *clk_name; + int ret; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return ERR_PTR(-ENOMEM); + + clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); + if (!clk_name) + return ERR_PTR(-ENOMEM); + + init.name = clk_name; + init.ops = &axg_clk_no_ops; + init.flags = 0; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + hw->init = &init; + + ret = devm_clk_hw_register(dev, hw); + kfree(clk_name); + + return ret ? ERR_PTR(ret) : hw; +} + +static int axg_register_clk_hw_input(struct device *dev, + const char *name, + unsigned int clkid) +{ + struct clk *parent_clk = devm_clk_get(dev, name); + struct clk_hw *hw = NULL; + + if (IS_ERR(parent_clk)) { + int err = PTR_ERR(parent_clk); + + /* It is ok if an input clock is missing */ + if (err == -ENOENT) { + dev_dbg(dev, "%s not provided", name); + } else { + if (err != -EPROBE_DEFER) + dev_err(dev, "failed to get %s clock", name); + return err; + } + } else { + hw = axg_clk_hw_register_bypass(dev, name, + __clk_get_name(parent_clk)); + } + + if (IS_ERR(hw)) { + dev_err(dev, "failed to register %s clock", name); + return PTR_ERR(hw); + } + + axg_audio_hw_onecell_data.hws[clkid] = hw; + return 0; +} + +static int axg_register_clk_hw_inputs(struct device *dev, + const char *basename, + unsigned int count, + unsigned int clkid) +{ + char *name; + int i, ret; + + for (i = 0; i < count; i++) { + name = kasprintf(GFP_KERNEL, "%s%d", basename, i); + if (!name) + return -ENOMEM; + + ret = axg_register_clk_hw_input(dev, name, clkid + i); + kfree(name); + if (ret) + return ret; + } + + return 0; +} + +static const struct regmap_config axg_audio_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = AUDIO_CLK_PDMIN_CTRL1, +}; + +static int axg_audio_clkc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *map; + struct resource *res; + void __iomem *regs; + struct clk *clk; + struct clk_hw *hw; + int ret, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg); + if (IS_ERR(map)) { + dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map)); + return PTR_ERR(map); + } + + /* Get the mandatory peripheral clock */ + clk = devm_clk_get_enable(dev, "pclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = device_reset(dev); + if (ret) { + dev_err(dev, "failed to reset device\n"); + return ret; + } + + /* Register the peripheral input clock */ + hw = axg_clk_hw_register_bypass(dev, "audio_pclk", + __clk_get_name(clk)); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw; + + /* Register optional input master clocks */ + ret = axg_register_clk_hw_inputs(dev, "mst_in", + AXG_MST_IN_COUNT, + AUD_CLKID_MST0); + if (ret) + return ret; + + /* Register optional input slave sclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_sclk", + AXG_SLV_SCLK_COUNT, + AUD_CLKID_SLV_SCLK0); + if (ret) + return ret; + + /* Register optional input slave lrclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", + AXG_SLV_LRCLK_COUNT, + AUD_CLKID_SLV_LRCLK0); + if (ret) + return ret; + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++) + axg_audio_clk_regmaps[i]->map = map; + + /* Take care to skip the registered input clocks */ + for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { + hw = axg_audio_hw_onecell_data.hws[i]; + /* array might be sparse */ + if (!hw) + continue; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "failed to register clock %s\n", + hw->init->name); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &axg_audio_hw_onecell_data); +} + +static const struct of_device_id clkc_match_table[] = { + { .compatible = "amlogic,axg-audio-clkc" }, + {} +}; +MODULE_DEVICE_TABLE(of, clkc_match_table); + +static struct platform_driver axg_audio_driver = { + .probe = axg_audio_clkc_probe, + .driver = { + .name = "axg-audio-clkc", + .of_match_table = clkc_match_table, + }, +}; +module_platform_driver(axg_audio_driver); + +MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h new file mode 100644 index 000000000000..7191b39c9d65 --- /dev/null +++ b/drivers/clk/meson/axg-audio.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __AXG_AUDIO_CLKC_H +#define __AXG_AUDIO_CLKC_H + +/* + * Audio Clock register offsets + * + * Register offsets from the datasheet must be multiplied by 4 before + * to get the right offset + */ +#define AUDIO_CLK_GATE_EN 0x000 +#define AUDIO_MCLK_A_CTRL 0x004 +#define AUDIO_MCLK_B_CTRL 0x008 +#define AUDIO_MCLK_C_CTRL 0x00C +#define AUDIO_MCLK_D_CTRL 0x010 +#define AUDIO_MCLK_E_CTRL 0x014 +#define AUDIO_MCLK_F_CTRL 0x018 +#define AUDIO_MST_A_SCLK_CTRL0 0x040 +#define AUDIO_MST_A_SCLK_CTRL1 0x044 +#define AUDIO_MST_B_SCLK_CTRL0 0x048 +#define AUDIO_MST_B_SCLK_CTRL1 0x04C +#define AUDIO_MST_C_SCLK_CTRL0 0x050 +#define AUDIO_MST_C_SCLK_CTRL1 0x054 +#define AUDIO_MST_D_SCLK_CTRL0 0x058 +#define AUDIO_MST_D_SCLK_CTRL1 0x05C +#define AUDIO_MST_E_SCLK_CTRL0 0x060 +#define AUDIO_MST_E_SCLK_CTRL1 0x064 +#define AUDIO_MST_F_SCLK_CTRL0 0x068 +#define AUDIO_MST_F_SCLK_CTRL1 0x06C +#define AUDIO_CLK_TDMIN_A_CTRL 0x080 +#define AUDIO_CLK_TDMIN_B_CTRL 0x084 +#define AUDIO_CLK_TDMIN_C_CTRL 0x088 +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08C +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090 +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094 +#define AUDIO_CLK_TDMOUT_C_CTRL 0x098 +#define AUDIO_CLK_SPDIFIN_CTRL 0x09C +#define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0 +#define AUDIO_CLK_RESAMPLE_CTRL 0x0A4 +#define AUDIO_CLK_LOCKER_CTRL 0x0A8 +#define AUDIO_CLK_PDMIN_CTRL0 0x0AC +#define AUDIO_CLK_PDMIN_CTRL1 0x0B0 + +/* + * CLKID index values + * These indices are entirely contrived and do not map onto the hardware. + */ + +#define AUD_CLKID_PCLK 0 +#define AUD_CLKID_MST0 1 +#define AUD_CLKID_MST1 2 +#define AUD_CLKID_MST2 3 +#define AUD_CLKID_MST3 4 +#define AUD_CLKID_MST4 5 +#define AUD_CLKID_MST5 6 +#define AUD_CLKID_MST6 7 +#define AUD_CLKID_MST7 8 +#define AUD_CLKID_MST_A_MCLK_SEL 59 +#define AUD_CLKID_MST_B_MCLK_SEL 60 +#define AUD_CLKID_MST_C_MCLK_SEL 61 +#define AUD_CLKID_MST_D_MCLK_SEL 62 +#define AUD_CLKID_MST_E_MCLK_SEL 63 +#define AUD_CLKID_MST_F_MCLK_SEL 64 +#define AUD_CLKID_MST_A_MCLK_DIV 65 +#define AUD_CLKID_MST_B_MCLK_DIV 66 +#define AUD_CLKID_MST_C_MCLK_DIV 67 +#define AUD_CLKID_MST_D_MCLK_DIV 68 +#define AUD_CLKID_MST_E_MCLK_DIV 69 +#define AUD_CLKID_MST_F_MCLK_DIV 70 +#define AUD_CLKID_SPDIFOUT_CLK_SEL 71 +#define AUD_CLKID_SPDIFOUT_CLK_DIV 72 +#define AUD_CLKID_SPDIFIN_CLK_SEL 73 +#define AUD_CLKID_SPDIFIN_CLK_DIV 74 +#define AUD_CLKID_PDM_DCLK_SEL 75 +#define AUD_CLKID_PDM_DCLK_DIV 76 +#define AUD_CLKID_PDM_SYSCLK_SEL 77 +#define AUD_CLKID_PDM_SYSCLK_DIV 78 +#define AUD_CLKID_MST_A_SCLK_PRE_EN 92 +#define AUD_CLKID_MST_B_SCLK_PRE_EN 93 +#define AUD_CLKID_MST_C_SCLK_PRE_EN 94 +#define AUD_CLKID_MST_D_SCLK_PRE_EN 95 +#define AUD_CLKID_MST_E_SCLK_PRE_EN 96 +#define AUD_CLKID_MST_F_SCLK_PRE_EN 97 +#define AUD_CLKID_MST_A_SCLK_DIV 98 +#define AUD_CLKID_MST_B_SCLK_DIV 99 +#define AUD_CLKID_MST_C_SCLK_DIV 100 +#define AUD_CLKID_MST_D_SCLK_DIV 101 +#define AUD_CLKID_MST_E_SCLK_DIV 102 +#define AUD_CLKID_MST_F_SCLK_DIV 103 +#define AUD_CLKID_MST_A_SCLK_POST_EN 104 +#define AUD_CLKID_MST_B_SCLK_POST_EN 105 +#define AUD_CLKID_MST_C_SCLK_POST_EN 106 +#define AUD_CLKID_MST_D_SCLK_POST_EN 107 +#define AUD_CLKID_MST_E_SCLK_POST_EN 108 +#define AUD_CLKID_MST_F_SCLK_POST_EN 109 +#define AUD_CLKID_MST_A_LRCLK_DIV 110 +#define AUD_CLKID_MST_B_LRCLK_DIV 111 +#define AUD_CLKID_MST_C_LRCLK_DIV 112 +#define AUD_CLKID_MST_D_LRCLK_DIV 113 +#define AUD_CLKID_MST_E_LRCLK_DIV 114 +#define AUD_CLKID_MST_F_LRCLK_DIV 115 +#define AUD_CLKID_TDMIN_A_SCLK_PRE_EN 137 +#define AUD_CLKID_TDMIN_B_SCLK_PRE_EN 138 +#define AUD_CLKID_TDMIN_C_SCLK_PRE_EN 139 +#define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN 140 +#define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN 141 +#define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN 142 +#define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN 143 +#define AUD_CLKID_TDMIN_A_SCLK_POST_EN 144 +#define AUD_CLKID_TDMIN_B_SCLK_POST_EN 145 +#define AUD_CLKID_TDMIN_C_SCLK_POST_EN 146 +#define AUD_CLKID_TDMIN_LB_SCLK_POST_EN 147 +#define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148 +#define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149 +#define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150 + +/* include the CLKIDs which are part of the DT bindings */ +#include + +#define NR_CLKS 151 + +#endif /*__AXG_AUDIO_CLKC_H */ From 9799d5ae003c05f0db5d6c5884183a388b74ba3c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 20 Jun 2018 12:06:09 +0200 Subject: [PATCH 55/85] clk: meson: stop rate propagation for audio clocks It is actually a lot easier to setup the PLL with carefully chosen rates than relying on CCF clock propagation for this audio use case. This way, we can make sure we will always be able to provide the common audio clock rates, while having the PLL in the optimal operating range. For this, we stop the rate propagation at the mux picking the PLL and let it round to the closest matching PLL. Doing so, we can use the generic divider for the i2s clock. clk-audio-divider is no longer required. It was a (poor) attempt to use CCF rate propagation while making sure the PLL rate would be high enough to work with audio use cases. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 297ebc391475..894a6adaa17a 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -970,28 +970,26 @@ static struct clk_regmap gxbb_cts_amclk_sel = { .mask = 0x3, .shift = 9, .table = (u32[]){ 1, 2, 3 }, + .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, - .flags = CLK_SET_RATE_PARENT, }, }; static struct clk_regmap gxbb_cts_amclk_div = { - .data = &(struct meson_clk_audio_div_data){ - .div = { - .reg_off = HHI_AUD_CLK_CNTL, - .shift = 0, - .width = 8, - }, + .data = &(struct clk_regmap_div_data) { + .offset = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, .flags = CLK_DIVIDER_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", - .ops = &meson_clk_audio_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "cts_amclk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1018,13 +1016,13 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = { .mask = 0x3, .shift = 25, .table = (u32[]){ 1, 2, 3 }, + .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, - .flags = CLK_SET_RATE_PARENT, }, }; From 85ddc1a32cace10bc8b7dc5dfae98b6a1785fc0c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 20 Jun 2018 12:06:10 +0200 Subject: [PATCH 56/85] clk: meson: remove unused clk-audio-divider driver clk-audio-divider is no longer used, we can remove it. Acked-by: Neil Armstrong Signed-off-by: Jerome Brunet --- drivers/clk/meson/Makefile | 3 +- drivers/clk/meson/clk-audio-divider.c | 110 -------------------------- drivers/clk/meson/clkc.h | 7 -- 3 files changed, 1 insertion(+), 119 deletions(-) delete mode 100644 drivers/clk/meson/clk-audio-divider.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index fd97f5ba317d..72ec8c40d848 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,8 +2,7 @@ # Makefile for Meson specific clk # -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c deleted file mode 100644 index e4cf96ba704e..000000000000 --- a/drivers/clk/meson/clk-audio-divider.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2017 AmLogic, Inc. - * Author: Jerome Brunet - */ - -/* - * i2s master clock divider: The algorithm of the generic clk-divider used with - * a very precise clock parent such as the mpll tends to select a low divider - * factor. This gives poor results with this particular divider, especially with - * high frequencies (> 100 MHz) - * - * This driver try to select the maximum possible divider with the rate the - * upstream clock can provide. - */ - -#include -#include "clkc.h" - -static inline struct meson_clk_audio_div_data * -meson_clk_audio_div_data(struct clk_regmap *clk) -{ - return (struct meson_clk_audio_div_data *)clk->data; -} - -static int _div_round(unsigned long parent_rate, unsigned long rate, - unsigned long flags) -{ - if (flags & CLK_DIVIDER_ROUND_CLOSEST) - return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, rate); - - return DIV_ROUND_UP_ULL((u64)parent_rate, rate); -} - -static int _get_val(unsigned long parent_rate, unsigned long rate) -{ - return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; -} - -static int _valid_divider(unsigned int width, int divider) -{ - int max_divider = 1 << width; - - return clamp(divider, 1, max_divider); -} - -static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); - unsigned long divider; - - divider = meson_parm_read(clk->map, &adiv->div) + 1; - - return DIV_ROUND_UP_ULL((u64)parent_rate, divider); -} - -static long audio_divider_round_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long *parent_rate) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); - unsigned long max_prate; - int divider; - - if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { - divider = _div_round(*parent_rate, rate, adiv->flags); - divider = _valid_divider(adiv->div.width, divider); - return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); - } - - /* Get the maximum parent rate */ - max_prate = clk_hw_round_rate(clk_hw_get_parent(hw), ULONG_MAX); - - /* Get the corresponding rounded down divider */ - divider = max_prate / rate; - divider = _valid_divider(adiv->div.width, divider); - - /* Get actual rate of the parent */ - *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), - divider * rate); - - return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); -} - -static int audio_divider_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); - int val = _get_val(parent_rate, rate); - - meson_parm_write(clk->map, &adiv->div, val); - - return 0; -} - -const struct clk_ops meson_clk_audio_divider_ro_ops = { - .recalc_rate = audio_divider_recalc_rate, - .round_rate = audio_divider_round_rate, -}; - -const struct clk_ops meson_clk_audio_divider_ops = { - .recalc_rate = audio_divider_recalc_rate, - .round_rate = audio_divider_round_rate, - .set_rate = audio_divider_set_rate, -}; diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index fd520ccdd1be..24cec16b6038 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -91,11 +91,6 @@ struct meson_clk_mpll_data { #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) -struct meson_clk_audio_div_data { - struct parm div; - u8 flags; -}; - struct meson_clk_phase_data { struct parm ph; }; @@ -124,8 +119,6 @@ extern const struct clk_ops meson_clk_pll_ops; extern const struct clk_ops meson_clk_cpu_ops; extern const struct clk_ops meson_clk_mpll_ro_ops; extern const struct clk_ops meson_clk_mpll_ops; -extern const struct clk_ops meson_clk_audio_divider_ro_ops; -extern const struct clk_ops meson_clk_audio_divider_ops; extern const struct clk_ops meson_clk_phase_ops; #endif /* __CLKC_H */ From cddcb20b2bb36401e038d0ae41ba8a956d91f82e Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Mon, 2 Jul 2018 21:31:18 +0000 Subject: [PATCH 57/85] clk: meson-axg: add clocks required by pcie driver Adding clocks for the pcie driver. Due to the ASIC design, the pcie controller re-use part of the mipi clock logic, so the mipi clock is also added. Tested-by: Jianxin Qin Signed-off-by: Yixun Lan [amended to remove unnecessary locales] Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 145 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/axg.h | 6 +- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 3fb884db1b10..2d458092884a 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -625,6 +625,137 @@ static struct clk_regmap axg_mpll3 = { }, }; +static const struct pll_rate_table axg_pcie_pll_rate_table[] = { + { + .rate = 100000000, + .m = 200, + .n = 3, + .od = 1, + .od2 = 3, + }, + { /* sentinel */ }, +}; + +static const struct reg_sequence axg_pcie_init_regs[] = { + { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, + { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, + { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, + { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, +}; + +static struct clk_regmap axg_pcie_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .od2 = { + .reg_off = HHI_PCIE_PLL_CNTL6, + .shift = 6, + .width = 2, + }, + .frac = { + .reg_off = HHI_PCIE_PLL_CNTL1, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_pcie_pll_rate_table, + .init_regs = axg_pcie_init_regs, + .init_count = ARRAY_SIZE(axg_pcie_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_pcie_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .mask = 0x1, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_mux", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "mpll3", "pcie_pll" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_ref = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .mask = 0x1, + .shift = 1, + /* skip the parent 0, reserved for debug */ + .table = (u32[]){ 1 }, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "pcie_mux" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_cml_en0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "pcie_ref" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + + }, +}; + +static struct clk_regmap axg_pcie_cml_en1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "pcie_cml_en1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "pcie_ref" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", @@ -820,6 +951,7 @@ static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11); static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); +static MESON_GATE(axg_mipi_enable, HHI_MIPI_CNTL0, 29); /* Always On (AO) domain gates */ @@ -909,6 +1041,13 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, + [CLKID_PCIE_PLL] = &axg_pcie_pll.hw, + [CLKID_PCIE_MUX] = &axg_pcie_mux.hw, + [CLKID_PCIE_REF] = &axg_pcie_ref.hw, + [CLKID_PCIE_CML_EN0] = &axg_pcie_cml_en0.hw, + [CLKID_PCIE_CML_EN1] = &axg_pcie_cml_en1.hw, + [CLKID_MIPI_ENABLE] = &axg_mipi_enable.hw, + [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -987,6 +1126,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_fclk_div4, &axg_fclk_div5, &axg_fclk_div7, + &axg_pcie_pll, + &axg_pcie_mux, + &axg_pcie_ref, + &axg_pcie_cml_en0, + &axg_pcie_cml_en1, + &axg_mipi_enable, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index b421df6a7ea0..6e55ebd6c77d 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -16,6 +16,7 @@ * Register offsets from the data sheet must be multiplied by 4 before * adding them to the base address to get the right value. */ +#define HHI_MIPI_CNTL0 0x00 #define HHI_GP0_PLL_CNTL 0x40 #define HHI_GP0_PLL_CNTL2 0x44 #define HHI_GP0_PLL_CNTL3 0x48 @@ -127,8 +128,11 @@ #define CLKID_FCLK_DIV4_DIV 73 #define CLKID_FCLK_DIV5_DIV 74 #define CLKID_FCLK_DIV7_DIV 75 +#define CLKID_PCIE_PLL 76 +#define CLKID_PCIE_MUX 77 +#define CLKID_PCIE_REF 78 -#define NR_CLKS 76 +#define NR_CLKS 82 /* include the CLKIDs that have been made part of the DT binding */ #include From 80d396b5118f448cb2206a509aba6917691a835e Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 4 Jul 2018 18:54:56 +0200 Subject: [PATCH 58/85] clk: meson: gxbb: remove HHI_GEN_CLK_CTNL duplicate definition HHI_GEN_CLK_CTNL is defined twice, just remove the duplicate definition Fixes: 738f66d3211d ("clk: gxbb: add AmLogic GXBB clk controller driver") Acked-by: Martin Blumenstingl Signed-off-by: Jerome Brunet --- drivers/clk/meson/gxbb.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index ec1a812bf1fd..df6c21d368c6 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -66,7 +66,6 @@ #define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */ #define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */ #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ -#define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ #define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ #define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ From 7df533a7e3d2216e860ecf147ae8cee49bf133e9 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 4 Jul 2018 18:54:58 +0200 Subject: [PATCH 59/85] clk: meson: add gen_clk GEN_CLK is able to route several internal clocks to one of the SoC pads. In the future, even more clocks could be made accessible using cts_msr_clk - the clock measure block. Signed-off-by: Jerome Brunet --- drivers/clk/meson/axg.c | 64 +++++++++++++++++++++++++++++++++++++- drivers/clk/meson/axg.h | 4 ++- drivers/clk/meson/gxbb.c | 66 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/gxbb.h | 4 ++- 4 files changed, 135 insertions(+), 3 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 2d458092884a..00ce62ad6416 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -909,6 +909,63 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { }, }; +static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, + 9, 10, 11, 13, 14, }; +static const char * const gen_clk_parent_names[] = { + "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", +}; + +static struct clk_regmap axg_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_GEN_CLK_CNTL, + .mask = 0xf, + .shift = 12, + .table = mux_table_gen_clk, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 15:12 selects from 14 possible parents: + * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], + * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ + .parent_names = gen_clk_parent_names, + .num_parents = ARRAY_SIZE(gen_clk_parent_names), + }, +}; + +static struct clk_regmap axg_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GEN_CLK_CNTL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gen_clk_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_GEN_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "gen_clk_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); @@ -1047,7 +1104,9 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_PCIE_CML_EN0] = &axg_pcie_cml_en0.hw, [CLKID_PCIE_CML_EN1] = &axg_pcie_cml_en1.hw, [CLKID_MIPI_ENABLE] = &axg_mipi_enable.hw, - + [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, + [CLKID_GEN_CLK] = &axg_gen_clk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1132,6 +1191,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_pcie_cml_en0, &axg_pcie_cml_en1, &axg_mipi_enable, + &axg_gen_clk_sel, + &axg_gen_clk_div, + &axg_gen_clk, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index 6e55ebd6c77d..1d04144a1b2c 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -131,8 +131,10 @@ #define CLKID_PCIE_PLL 76 #define CLKID_PCIE_MUX 77 #define CLKID_PCIE_REF 78 +#define CLKID_GEN_CLK_SEL 82 +#define CLKID_GEN_CLK_DIV 83 -#define NR_CLKS 82 +#define NR_CLKS 85 /* include the CLKIDs that have been made part of the DT binding */ #include diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 894a6adaa17a..86d3ae58e84c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -1624,6 +1624,63 @@ static struct clk_regmap gxbb_vdec_hevc = { }, }; +static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, + 9, 10, 11, 13, 14, }; +static const char * const gen_clk_parent_names[] = { + "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", +}; + +static struct clk_regmap gxbb_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_GEN_CLK_CNTL, + .mask = 0xf, + .shift = 12, + .table = mux_table_gen_clk, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + /* + * bits 15:12 selects from 14 possible parents: + * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], + * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, + * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll + */ + .parent_names = gen_clk_parent_names, + .num_parents = ARRAY_SIZE(gen_clk_parent_names), + }, +}; + +static struct clk_regmap gxbb_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GEN_CLK_CNTL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gen_clk_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_GEN_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "gen_clk_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); @@ -1873,6 +1930,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, + [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, + [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2035,6 +2095,9 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, + [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, + [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, + [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -2199,6 +2262,9 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_vdec_hevc_sel, &gxbb_vdec_hevc_div, &gxbb_vdec_hevc, + &gxbb_gen_clk_sel, + &gxbb_gen_clk_div, + &gxbb_gen_clk, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index df6c21d368c6..20dfb1daf5b8 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -157,8 +157,10 @@ #define CLKID_VDEC_1_DIV 152 #define CLKID_VDEC_HEVC_SEL 154 #define CLKID_VDEC_HEVC_DIV 155 +#define CLKID_GEN_CLK_SEL 157 +#define CLKID_GEN_CLK_DIV 158 -#define NR_CLKS 157 +#define NR_CLKS 160 /* include the CLKIDs that have been made part of the DT binding */ #include From 66c7bb7c4133c5cc4e9962d5951bf3bd65e29120 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 19 Jun 2018 14:34:46 +0200 Subject: [PATCH 60/85] clk: mvebu: armada-37xx-periph: switch to SPDX license identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 6860bd5a37c5..c179eff6a7e9 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Marvell Armada 37xx SoC Peripheral clocks * @@ -5,10 +6,6 @@ * * Gregory CLEMENT * - * This file is licensed under the terms of the GNU General Public - * License version 2 or later. This program is licensed "as is" - * without any warranty of any kind, whether express or implied. - * * Most of the peripheral clocks can be modelled like this: * _____ _______ _______ * TBG-A-P --| | | | | | ______ From 30343897d8fd84c630ee2c7f5b38c16da2c7ee4b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 15 Jun 2018 11:51:04 +0200 Subject: [PATCH 61/85] clk: imx7d: add IMX7D_MU_ROOT_CLK This clock is needed for iMX mailbox driver Signed-off-by: Oleksij Rempel Reviewed-by: Dong Aisheng Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 27217a7ea17e..881b772c4ac9 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -797,6 +797,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0); clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0); clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0); + clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0); clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0); clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0); clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); From 9c7e47025a6b9a2800eec127996ad58946e0cad4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 9 May 2018 11:26:07 +0530 Subject: [PATCH 62/85] clk: qcom: clk-rpmh: Add QCOM RPMh clock driver Add the RPMh clock driver to control the RPMh managed clock resources on some of the Qualcomm Technologies, Inc. SoCs. Signed-off-by: Taniya Das [sboyd@kernel.org: Clean up whitespace, indentation, remove cmd_db_ready check] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rpmh.c | 329 ++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/clk/qcom/clk-rpmh.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9c3480dcc38a..2b69cf22b323 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -59,6 +59,15 @@ config QCOM_CLK_SMD_RPM Say Y if you want to support the clocks exposed by the RPM on platforms such as apq8016, apq8084, msm8974 etc. +config QCOM_CLK_RPMH + tristate "RPMh Clock Driver" + depends on COMMON_CLK_QCOM && QCOM_RPMH + help + RPMh manages shared resources on some Qualcomm Technologies, Inc. + SoCs. It accepts requests from other hardware subsystems via RSC. + Say Y if you want to support the clocks exposed by RPMh on + platforms such as SDM845. + config APQ_GCC_8084 tristate "APQ8084 Global Clock Controller" select QCOM_GDSC diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 762c01137c2f..599ab9154480 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o +obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c new file mode 100644 index 000000000000..9f4fc7773fb2 --- /dev/null +++ b/drivers/clk/qcom/clk-rpmh.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CLK_RPMH_ARC_EN_OFFSET 0 +#define CLK_RPMH_VRM_EN_OFFSET 4 + +/** + * struct clk_rpmh - individual rpmh clock data structure + * @hw: handle between common and hardware-specific interfaces + * @res_name: resource name for the rpmh clock + * @div: clock divider to compute the clock rate + * @res_addr: base address of the rpmh resource within the RPMh + * @res_on_val: rpmh clock enable value + * @state: rpmh clock requested state + * @aggr_state: rpmh clock aggregated state + * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh + * @valid_state_mask: mask to determine the state of the rpmh clock + * @dev: device to which it is attached + * @peer: pointer to the clock rpmh sibling + */ +struct clk_rpmh { + struct clk_hw hw; + const char *res_name; + u8 div; + u32 res_addr; + u32 res_on_val; + u32 state; + u32 aggr_state; + u32 last_sent_aggr_state; + u32 valid_state_mask; + struct device *dev; + struct clk_rpmh *peer; +}; + +struct clk_rpmh_desc { + struct clk_hw **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpmh_clk_lock); + +#define __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ + _res_en_offset, _res_on, _div) \ + static struct clk_rpmh _platform##_##_name_active; \ + static struct clk_rpmh _platform##_##_name = { \ + .res_name = _res_name, \ + .res_addr = _res_en_offset, \ + .res_on_val = _res_on, \ + .div = _div, \ + .peer = &_platform##_##_name_active, \ + .valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \ + BIT(RPMH_ACTIVE_ONLY_STATE) | \ + BIT(RPMH_SLEEP_STATE)), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpmh_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpmh _platform##_##_name_active = { \ + .res_name = _res_name, \ + .res_addr = _res_en_offset, \ + .res_on_val = _res_on, \ + .div = _div, \ + .peer = &_platform##_##_name, \ + .valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \ + BIT(RPMH_ACTIVE_ONLY_STATE)), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpmh_ops, \ + .name = #_name_active, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_RPMH_ARC(_platform, _name, _name_active, _res_name, \ + _res_on, _div) \ + __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ + CLK_RPMH_ARC_EN_OFFSET, _res_on, _div) + +#define DEFINE_CLK_RPMH_VRM(_platform, _name, _name_active, _res_name, \ + _div) \ + __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ + CLK_RPMH_VRM_EN_OFFSET, 1, _div) + +static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) +{ + return container_of(_hw, struct clk_rpmh, hw); +} + +static inline bool has_state_changed(struct clk_rpmh *c, u32 state) +{ + return (c->last_sent_aggr_state & BIT(state)) + != (c->aggr_state & BIT(state)); +} + +static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c) +{ + struct tcs_cmd cmd = { 0 }; + u32 cmd_state, on_val; + enum rpmh_state state = RPMH_SLEEP_STATE; + int ret; + + cmd.addr = c->res_addr; + cmd_state = c->aggr_state; + on_val = c->res_on_val; + + for (; state <= RPMH_ACTIVE_ONLY_STATE; state++) { + if (has_state_changed(c, state)) { + if (cmd_state & BIT(state)) + cmd.data = on_val; + + ret = rpmh_write_async(c->dev, state, &cmd, 1); + if (ret) { + dev_err(c->dev, "set %s state of %s failed: (%d)\n", + !state ? "sleep" : + state == RPMH_WAKE_ONLY_STATE ? + "wake" : "active", c->res_name, ret); + return ret; + } + } + } + + c->last_sent_aggr_state = c->aggr_state; + c->peer->last_sent_aggr_state = c->last_sent_aggr_state; + + return 0; +} + +/* + * Update state and aggregate state values based on enable value. + */ +static int clk_rpmh_aggregate_state_send_command(struct clk_rpmh *c, + bool enable) +{ + int ret; + + /* Nothing required to be done if already off or on */ + if (enable == c->state) + return 0; + + c->state = enable ? c->valid_state_mask : 0; + c->aggr_state = c->state | c->peer->state; + c->peer->aggr_state = c->aggr_state; + + ret = clk_rpmh_send_aggregate_command(c); + if (!ret) + return 0; + + if (ret && enable) + c->state = 0; + else if (ret) + c->state = c->valid_state_mask; + + WARN(1, "clk: %s failed to %s\n", c->res_name, + enable ? "enable" : "disable"); + return ret; +} + +static int clk_rpmh_prepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + int ret = 0; + + mutex_lock(&rpmh_clk_lock); + ret = clk_rpmh_aggregate_state_send_command(c, true); + mutex_unlock(&rpmh_clk_lock); + + return ret; +}; + +static void clk_rpmh_unprepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + mutex_lock(&rpmh_clk_lock); + clk_rpmh_aggregate_state_send_command(c, false); + mutex_unlock(&rpmh_clk_lock); +}; + +static unsigned long clk_rpmh_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_rpmh *r = to_clk_rpmh(hw); + + /* + * RPMh clocks have a fixed rate. Return static rate. + */ + return prate / r->div; +} + +static const struct clk_ops clk_rpmh_ops = { + .prepare = clk_rpmh_prepare, + .unprepare = clk_rpmh_unprepare, + .recalc_rate = clk_rpmh_recalc_rate, +}; + +/* Resource name must match resource id present in cmd-db. */ +DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); +DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); +DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2); +DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); +DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); +DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); + +static struct clk_hw *sdm845_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, + [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw, + [RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw, + [RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw, + [RPMH_LN_BB_CLK3] = &sdm845_ln_bb_clk3.hw, + [RPMH_LN_BB_CLK3_A] = &sdm845_ln_bb_clk3_ao.hw, + [RPMH_RF_CLK1] = &sdm845_rf_clk1.hw, + [RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw, + [RPMH_RF_CLK2] = &sdm845_rf_clk2.hw, + [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, + [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, + [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sdm845 = { + .clks = sdm845_rpmh_clocks, + .num_clks = ARRAY_SIZE(sdm845_rpmh_clocks), +}; + +static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, + void *data) +{ + struct clk_rpmh_desc *rpmh = data; + unsigned int idx = clkspec->args[0]; + + if (idx >= rpmh->num_clks) { + pr_err("%s: invalid index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + return rpmh->clks[idx]; +} + +static int clk_rpmh_probe(struct platform_device *pdev) +{ + struct clk_hw **hw_clks; + struct clk_rpmh *rpmh_clk; + const struct clk_rpmh_desc *desc; + int ret, i; + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -ENODEV; + + hw_clks = desc->clks; + + for (i = 0; i < desc->num_clks; i++) { + u32 res_addr; + + rpmh_clk = to_clk_rpmh(hw_clks[i]); + res_addr = cmd_db_read_addr(rpmh_clk->res_name); + if (!res_addr) { + dev_err(&pdev->dev, "missing RPMh resource address for %s\n", + rpmh_clk->res_name); + return -ENODEV; + } + rpmh_clk->res_addr += res_addr; + rpmh_clk->dev = &pdev->dev; + + ret = devm_clk_hw_register(&pdev->dev, hw_clks[i]); + if (ret) { + dev_err(&pdev->dev, "failed to register %s\n", + hw_clks[i]->init->name); + return ret; + } + } + + /* typecast to silence compiler warning */ + ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_rpmh_hw_get, + (void *)desc); + if (ret) { + dev_err(&pdev->dev, "Failed to add clock provider\n"); + return ret; + } + + dev_dbg(&pdev->dev, "Registered RPMh clocks\n"); + + return 0; +} + +static const struct of_device_id clk_rpmh_match_table[] = { + { .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845}, + { } +}; +MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); + +static struct platform_driver clk_rpmh_driver = { + .probe = clk_rpmh_probe, + .driver = { + .name = "clk-rpmh", + .of_match_table = clk_rpmh_match_table, + }, +}; + +static int __init clk_rpmh_init(void) +{ + return platform_driver_register(&clk_rpmh_driver); +} +subsys_initcall(clk_rpmh_init); + +static void __exit clk_rpmh_exit(void) +{ + platform_driver_unregister(&clk_rpmh_driver); +} +module_exit(clk_rpmh_exit); + +MODULE_DESCRIPTION("QCOM RPMh Clock Driver"); +MODULE_LICENSE("GPL v2"); From f9419783a6b45a7198ea22f2997cf1a85fda8458 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 16 Jul 2018 11:24:32 +0530 Subject: [PATCH 63/85] clk: qcom: Update SPDX headers for common files SPDX headers updated for common/branch/pll/regmap files. Signed-off-by: Taniya Das Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-alpha-pll.c | 10 +--------- drivers/clk/qcom/clk-alpha-pll.h | 14 ++------------ drivers/clk/qcom/clk-branch.c | 10 +--------- drivers/clk/qcom/clk-branch.h | 14 ++------------ drivers/clk/qcom/clk-regmap.c | 10 +--------- drivers/clk/qcom/clk-regmap.h | 14 ++------------ drivers/clk/qcom/common.c | 10 +--------- drivers/clk/qcom/common.h | 15 +++------------ 8 files changed, 13 insertions(+), 84 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 3c49a60072f1..a91d97cecbad 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index f981b486c468..66755f0f84fc 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_ALPHA_PLL_H__ #define __QCOM_CLK_ALPHA_PLL_H__ diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index c58c5538b1b6..bc2205c450b6 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 1702efb1c511..b3561e0a3984 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_BRANCH_H__ #define __QCOM_CLK_BRANCH_H__ diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c index 1c856d330733..ce80db27ccf2 100644 --- a/drivers/clk/qcom/clk-regmap.c +++ b/drivers/clk/qcom/clk-regmap.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 90d95cd11ec6..6cfc1bccb255 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_REGMAP_H__ #define __QCOM_CLK_REGMAP_H__ diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 39ce64c2783b..db9b2471ac40 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 00196ee15e73..4aa33ee70bae 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -1,15 +1,6 @@ -/* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. */ + #ifndef __QCOM_CLK_COMMON_H__ #define __QCOM_CLK_COMMON_H__ From 365f7a89c881e84f1ebc925f65f899d5d7ce547e Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 11 Jul 2018 11:21:04 +0300 Subject: [PATCH 64/85] clk: core: Potentially free connection id Patch "clk: core: Copy connection id" made it so that the connector id 'con_id' is kstrdup_const()ed to cater to drivers that pass non-constant connection ids. The patch added the corresponding kfree_const to __clk_free_clk(), but struct clk's can be freed also via __clk_put(). Add the kfree_const call to __clk_put() and add comments to both functions to remind that the logic in them should be kept in sync. Fixes: 253160a8ad06 ("clk: core: Copy connection id") Signed-off-by: Mikko Perttunen Reviewed-by: Leonard Crestez Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9760b526ca31..eeec6885c302 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2934,6 +2934,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, return clk; } +/* keep in sync with __clk_put */ void __clk_free_clk(struct clk *clk) { clk_prepare_lock(); @@ -3313,6 +3314,7 @@ int __clk_get(struct clk *clk) return 1; } +/* keep in sync with __clk_free_clk */ void __clk_put(struct clk *clk) { struct module *owner; @@ -3346,6 +3348,7 @@ void __clk_put(struct clk *clk) module_put(owner); + kfree_const(clk->con_id); kfree(clk); } From f6dab4233d6b64d719109040503b567f71fbfa01 Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Tue, 17 Jul 2018 06:17:00 -0700 Subject: [PATCH 65/85] clk: clk-fixed-factor: Clear OF_POPULATED flag in case of failure Fixed factor clock has two initializations at of_clk_init() time and during platform driver probe. Before of_clk_init() call, node is marked as populated and so its probe never gets called. During of_clk_init() fixed factor clock registration may fail if any of its parent clock is not registered. In this case, it doesn't get chance to retry registration from probe. Clear OF_POPULATED flag if fixed factor clock registration fails so that clock registration is attempted again from probe. Signed-off-by: Rajan Vaja Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-factor.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index a5d402de5584..20724abd38bd 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -177,8 +177,15 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, mult, div); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + /* + * If parent clock is not registered, registration would fail. + * Clear OF_POPULATED flag so that clock registration can be + * attempted again from probe function. + */ + of_node_clear_flag(node, OF_POPULATED); return clk; + } ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); if (ret) { From 616bf80d381da13fbb392ebff06f46f946e3ee84 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 13 Jul 2018 12:27:26 +0200 Subject: [PATCH 66/85] clk: mvebu: armada-37xx-periph: Fix wrong return value in get_parent The return value of the get_parent operation is a u8, whereas a -EINVAL was returned. This wrong value was return if the value was bigger that the number of parent but this case was already handled by the core. So we can just remove this chunk of code to fix the issue. Reported-by: Dan Carpenter Fixes: 9818a7a4fd10 ("clk: mvebu: armada-37xx-periph: prepare cpu clk to be used with DVFS") Signed-off-by: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 6860bd5a37c5..5cf0a52b87e8 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -428,9 +428,6 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) val &= pm_cpu->mask_mux; } - if (val >= num_parents) - return -EINVAL; - return val; } From d7b7c00dad79f7cc78dac87a3ff2f06358518384 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 11 Jul 2018 08:58:58 +0800 Subject: [PATCH 67/85] clk: imx: add ocram_s clock for i.mx6sx i.MX6SX has a 16KB always-on ocram bank called ocram_s, and its clock gate in CCM CCGR1 CG14 needs to be enabled before access, add it to clock tree. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 10c771b91ef6..691db26bd09a 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -411,6 +411,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20); clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26); + clks[IMX6SX_CLK_OCRAM_S] = imx_clk_gate2("ocram_s", "ahb", base + 0x6c, 28); clks[IMX6SX_CLK_CANFD] = imx_clk_gate2("canfd", "can_podf", base + 0x6c, 30); /* CCGR2 */ From 11177e7a7aaef95935592072985526ebf0a3df43 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 13 Jul 2018 13:13:20 +0200 Subject: [PATCH 68/85] clk: imx6ul: fix missing of_node_put() of_find_compatible_node() is returning a device node with refcount incremented and must be explicitly decremented after the last use which is right after the us in of_iomap() here. Signed-off-by: Nicholas Mc Guire Fixes: 787b4271a6a0 ("clk: imx: add imx6ul clk tree support") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6ul.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index ba563ba50b40..9f1a40498642 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -142,6 +142,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop"); base = of_iomap(np, 0); + of_node_put(np); WARN_ON(!base); clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); From 7f5eac5934d747535f9ffc997792a0a6eb289374 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 13 Jul 2018 18:40:04 +0200 Subject: [PATCH 69/85] clk: imx6sll: fix missing of_node_put() of_find_compatible_node() is returning a device node with refcount incremented and must be explicitly decremented after the last use which is right after the us in of_iomap() here. Signed-off-by: Nicholas Mc Guire Fixes: 4a5f720b6542 ("clk: imx: add clock driver for imx6sll") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 3651c77fbabe..645d8a42007c 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -92,6 +92,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop"); base = of_iomap(np, 0); + of_node_put(np); WARN_ON(!base); /* Do not bypass PLLs initially */ From 0cbb61a313979b53d6b2dc838a92f07471440708 Mon Sep 17 00:00:00 2001 From: Aapo Vienamo Date: Thu, 12 Jul 2018 14:52:59 +0300 Subject: [PATCH 70/85] clk: tegra: Fix includes required by fence_udelay() Add the missing linux/delay.h include statement for udelay() used by fence_udelay() macro. Signed-off-by: Aapo Vienamo Acked-by: Peter De Schrijver Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index e1f88463b600..e3b9c22ad8b2 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -19,6 +19,7 @@ #include #include +#include /** * struct tegra_clk_sync_source - external clock source from codec From cb3ac5947afb3bb7e2f89c1b59f61dcf3e115fe1 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 12 Jul 2018 14:53:00 +0300 Subject: [PATCH 71/85] clk: tegra: Refactor fractional divider calculation Move this to a separate file so it can be used to calculate the sdmmc clock dividers. Signed-off-by: Peter De-Schrijver Signed-off-by: Aapo Vienamo Acked-by: Peter De Schrijver Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-divider.c | 32 +++++------------------- drivers/clk/tegra/clk-utils.c | 43 +++++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 3 +++ 4 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 drivers/clk/tegra/clk-utils.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index b71692391bd6..c77d072eb333 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o obj-y += cvb.o obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o obj-$(CONFIG_CLK_TEGRA_BPMP) += clk-bpmp.o +obj-y += clk-utils.o diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 16e0aee14773..8f175ff62f73 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -32,35 +32,15 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, unsigned long parent_rate) { - u64 divider_ux1 = parent_rate; - u8 flags = divider->flags; - int mul; + int div; - if (!rate) + div = div_frac_get(rate, parent_rate, divider->width, + divider->frac_width, divider->flags); + + if (div < 0) return 0; - mul = get_mul(divider); - - if (!(flags & TEGRA_DIVIDER_INT)) - divider_ux1 *= mul; - - if (flags & TEGRA_DIVIDER_ROUND_UP) - divider_ux1 += rate - 1; - - do_div(divider_ux1, rate); - - if (flags & TEGRA_DIVIDER_INT) - divider_ux1 *= mul; - - divider_ux1 -= mul; - - if ((s64)divider_ux1 < 0) - return 0; - - if (divider_ux1 > get_max_div(divider)) - return get_max_div(divider); - - return divider_ux1; + return div; } static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, diff --git a/drivers/clk/tegra/clk-utils.c b/drivers/clk/tegra/clk-utils.c new file mode 100644 index 000000000000..1a5daae4e501 --- /dev/null +++ b/drivers/clk/tegra/clk-utils.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + */ + +#include + +#include "clk.h" + +#define div_mask(w) ((1 << (w)) - 1) + +int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width, + u8 frac_width, u8 flags) +{ + u64 divider_ux1 = parent_rate; + int mul; + + if (!rate) + return 0; + + mul = 1 << frac_width; + + if (!(flags & TEGRA_DIVIDER_INT)) + divider_ux1 *= mul; + + if (flags & TEGRA_DIVIDER_ROUND_UP) + divider_ux1 += rate - 1; + + do_div(divider_ux1, rate); + + if (flags & TEGRA_DIVIDER_INT) + divider_ux1 *= mul; + + if (divider_ux1 < mul) + return 0; + + divider_ux1 -= mul; + + if (divider_ux1 > div_mask(width)) + return div_mask(width); + + return divider_ux1; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index e3b9c22ad8b2..c733841aa6db 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -812,6 +812,9 @@ extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll); u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate); int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div); +int div_frac_get(unsigned long rate, unsigned parent_rate, u8 width, + u8 frac_width, u8 flags); + /* Combined read fence with delay */ #define fence_udelay(delay, reg) \ From 633e79650b4f0ed8cd26076a376b5372c413b0f8 Mon Sep 17 00:00:00 2001 From: Peter De-Schrijver Date: Thu, 12 Jul 2018 14:53:01 +0300 Subject: [PATCH 72/85] clk: tegra: Add sdmmc mux divider clock Add a clock type to model the sdmmc switch divider clocks which have paths to source clocks bypassing the divider (Low Jitter paths). These are handled by selecting the lj path when the divider is 1 (ie the rate is the parent rate), otherwise the normal path with divider will be selected. Otherwise this clock behaves as a normal peripheral clock. Signed-off-by: Peter De-Schrijver Signed-off-by: Aapo Vienamo Acked-by: Peter De Schrijver Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-sdmmc-mux.c | 251 ++++++++++++++++++++++++++++++ drivers/clk/tegra/clk.h | 26 ++++ 3 files changed, 278 insertions(+) create mode 100644 drivers/clk/tegra/clk-sdmmc-mux.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index c77d072eb333..6507acc843c7 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -8,6 +8,7 @@ obj-y += clk-periph-fixed.o obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o +obj-y += clk-sdmmc-mux.o obj-y += clk-super.o obj-y += clk-tegra-audio.o obj-y += clk-tegra-periph.o diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c new file mode 100644 index 000000000000..473d418533cb --- /dev/null +++ b/drivers/clk/tegra/clk-sdmmc-mux.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 NVIDIA CORPORATION. All rights reserved. + * + * based on clk-mux.c + * + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * Copyright (C) 2011 Richard Zhao, Linaro + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd + * + */ + +#include +#include +#include + +#include "clk.h" + +#define DIV_MASK GENMASK(7, 0) +#define MUX_SHIFT 29 +#define MUX_MASK GENMASK(MUX_SHIFT + 2, MUX_SHIFT) +#define SDMMC_MUL 2 + +#define get_max_div(d) DIV_MASK +#define get_div_field(val) ((val) & DIV_MASK) +#define get_mux_field(val) (((val) & MUX_MASK) >> MUX_SHIFT) + +static const char * const mux_sdmmc_parents[] = { + "pll_p", "pll_c4_out2", "pll_c4_out0", "pll_c4_out1", "clk_m" +}; + +static const u8 mux_lj_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 5, [4] = 6 +}; + +static const u8 mux_non_lj_idx[] = { + [0] = 0, [1] = 3, [2] = 7, [3] = 4, [4] = 6 +}; + +static u8 clk_sdmmc_mux_get_parent(struct clk_hw *hw) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + int num_parents, i; + u32 src, val; + const u8 *mux_idx; + + num_parents = clk_hw_get_num_parents(hw); + + val = readl_relaxed(sdmmc_mux->reg); + src = get_mux_field(val); + if (get_div_field(val)) + mux_idx = mux_non_lj_idx; + else + mux_idx = mux_lj_idx; + + for (i = 0; i < num_parents; i++) { + if (mux_idx[i] == src) + return i; + } + + WARN(1, "Unknown parent selector %d\n", src); + + return 0; +} + +static int clk_sdmmc_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + u32 val; + + + val = readl_relaxed(sdmmc_mux->reg); + if (get_div_field(val)) + index = mux_non_lj_idx[index]; + else + index = mux_lj_idx[index]; + + val &= ~MUX_MASK; + val |= index << MUX_SHIFT; + + writel(val, sdmmc_mux->reg); + + return 0; +} + +static unsigned long clk_sdmmc_mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + u32 val; + int div; + u64 rate = parent_rate; + + val = readl_relaxed(sdmmc_mux->reg); + div = get_div_field(val); + + div += SDMMC_MUL; + + rate *= SDMMC_MUL; + rate += div - 1; + do_div(rate, div); + + return rate; +} + +static int clk_sdmmc_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + int div; + unsigned long output_rate = req->best_parent_rate; + + req->rate = max(req->rate, req->min_rate); + req->rate = min(req->rate, req->max_rate); + + if (!req->rate) + return output_rate; + + div = div_frac_get(req->rate, output_rate, 8, 1, sdmmc_mux->div_flags); + if (div < 0) + div = 0; + + if (sdmmc_mux->div_flags & TEGRA_DIVIDER_ROUND_UP) + req->rate = DIV_ROUND_UP(output_rate * SDMMC_MUL, + div + SDMMC_MUL); + else + req->rate = output_rate * SDMMC_MUL / (div + SDMMC_MUL); + + return 0; +} + +static int clk_sdmmc_mux_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + int div; + unsigned long flags = 0; + u32 val; + u8 src; + + div = div_frac_get(rate, parent_rate, 8, 1, sdmmc_mux->div_flags); + if (div < 0) + return div; + + if (sdmmc_mux->lock) + spin_lock_irqsave(sdmmc_mux->lock, flags); + + src = clk_sdmmc_mux_get_parent(hw); + if (div) + src = mux_non_lj_idx[src]; + else + src = mux_lj_idx[src]; + + val = src << MUX_SHIFT; + val |= div; + writel(val, sdmmc_mux->reg); + fence_udelay(2, sdmmc_mux->reg); + + if (sdmmc_mux->lock) + spin_unlock_irqrestore(sdmmc_mux->lock, flags); + + return 0; +} + +static int clk_sdmmc_mux_is_enabled(struct clk_hw *hw) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; + struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; + + __clk_hw_set_clk(gate_hw, hw); + + return gate_ops->is_enabled(gate_hw); +} + +static int clk_sdmmc_mux_enable(struct clk_hw *hw) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; + struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; + + __clk_hw_set_clk(gate_hw, hw); + + return gate_ops->enable(gate_hw); +} + +static void clk_sdmmc_mux_disable(struct clk_hw *hw) +{ + struct tegra_sdmmc_mux *sdmmc_mux = to_clk_sdmmc_mux(hw); + const struct clk_ops *gate_ops = sdmmc_mux->gate_ops; + struct clk_hw *gate_hw = &sdmmc_mux->gate.hw; + + gate_ops->disable(gate_hw); +} + +static const struct clk_ops tegra_clk_sdmmc_mux_ops = { + .get_parent = clk_sdmmc_mux_get_parent, + .set_parent = clk_sdmmc_mux_set_parent, + .determine_rate = clk_sdmmc_mux_determine_rate, + .recalc_rate = clk_sdmmc_mux_recalc_rate, + .set_rate = clk_sdmmc_mux_set_rate, + .is_enabled = clk_sdmmc_mux_is_enabled, + .enable = clk_sdmmc_mux_enable, + .disable = clk_sdmmc_mux_disable, +}; + +struct clk *tegra_clk_register_sdmmc_mux_div(const char *name, + void __iomem *clk_base, u32 offset, u32 clk_num, u8 div_flags, + unsigned long flags, void *lock) +{ + struct clk *clk; + struct clk_init_data init; + const struct tegra_clk_periph_regs *bank; + struct tegra_sdmmc_mux *sdmmc_mux; + + init.ops = &tegra_clk_sdmmc_mux_ops; + init.name = name; + init.flags = flags; + init.parent_names = mux_sdmmc_parents; + init.num_parents = ARRAY_SIZE(mux_sdmmc_parents); + + bank = get_reg_bank(clk_num); + if (!bank) + return ERR_PTR(-EINVAL); + + sdmmc_mux = kzalloc(sizeof(*sdmmc_mux), GFP_KERNEL); + if (!sdmmc_mux) + return ERR_PTR(-ENOMEM); + + /* Data in .init is copied by clk_register(), so stack variable OK */ + sdmmc_mux->hw.init = &init; + sdmmc_mux->reg = clk_base + offset; + sdmmc_mux->lock = lock; + sdmmc_mux->gate.clk_base = clk_base; + sdmmc_mux->gate.regs = bank; + sdmmc_mux->gate.enable_refcnt = periph_clk_enb_refcnt; + sdmmc_mux->gate.clk_num = clk_num; + sdmmc_mux->gate.flags = TEGRA_PERIPH_ON_APB; + sdmmc_mux->div_flags = div_flags; + sdmmc_mux->gate_ops = &tegra_clk_periph_gate_ops; + + clk = clk_register(NULL, &sdmmc_mux->hw); + if (IS_ERR(clk)) { + kfree(sdmmc_mux); + return clk; + } + + sdmmc_mux->gate.hw.clk = clk; + + return clk; +} diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index c733841aa6db..d2c3a010f8e9 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -706,6 +706,32 @@ struct clk *tegra_clk_register_super_clk(const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 clk_super_flags, spinlock_t *lock); + +/** + * struct tegra_sdmmc_mux - switch divider with Low Jitter inputs for SDMMC + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling mux and divider + * @flags: hardware-specific flags + * @lock: optional register lock + * @gate: gate clock + * @gate_ops: gate clock ops + */ +struct tegra_sdmmc_mux { + struct clk_hw hw; + void __iomem *reg; + spinlock_t *lock; + const struct clk_ops *gate_ops; + struct tegra_clk_periph_gate gate; + u8 div_flags; +}; + +#define to_clk_sdmmc_mux(_hw) container_of(_hw, struct tegra_sdmmc_mux, hw) + +struct clk *tegra_clk_register_sdmmc_mux_div(const char *name, + void __iomem *clk_base, u32 offset, u32 clk_num, u8 div_flags, + unsigned long flags, void *lock); + /** * struct clk_init_table - clock initialization table * @clk_id: clock id as mentioned in device tree bindings From c76a69e477b88f259bcc118129874011abcaae86 Mon Sep 17 00:00:00 2001 From: Peter De-Schrijver Date: Thu, 12 Jul 2018 14:53:02 +0300 Subject: [PATCH 73/85] clk: tegra: make sdmmc2 and sdmmc4 as sdmmc clocks These clocks have low jitter paths to certain parents. To model these correctly, use the sdmmc mux divider clock type. Signed-off-by: Peter De-Schrijver Signed-off-by: Aapo Vienamo Acked-by: Peter De Schrijver Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-id.h | 2 -- drivers/clk/tegra/clk-tegra-periph.c | 11 ----------- drivers/clk/tegra/clk-tegra210.c | 14 ++++++++++++-- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index b616e33c5255..de466b4446da 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -227,13 +227,11 @@ enum clk_id { tegra_clk_sdmmc1_9, tegra_clk_sdmmc2, tegra_clk_sdmmc2_8, - tegra_clk_sdmmc2_9, tegra_clk_sdmmc3, tegra_clk_sdmmc3_8, tegra_clk_sdmmc3_9, tegra_clk_sdmmc4, tegra_clk_sdmmc4_8, - tegra_clk_sdmmc4_9, tegra_clk_se, tegra_clk_soc_therm, tegra_clk_soc_therm_8, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 2acba2986bc6..38c4eb28c8bf 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -451,15 +451,6 @@ static u32 mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = { [0] = 0, [1] = 3, [2] = 4, [3] = 6, [4] = 7, }; -static const char *mux_pllp_clkm_pllc4_out2_out1_out0_lj[] = { - "pll_p", - "pll_c4_out2", "pll_c4_out0", /* LJ input */ - "pll_c4_out2", "pll_c4_out1", - "pll_c4_out1", /* LJ input */ - "clk_m", "pll_c4_out0" -}; -#define mux_pllp_clkm_pllc4_out2_out1_out0_lj_idx NULL - static const char *mux_pllp_pllc2_c_c3_clkm[] = { "pll_p", "pll_c2", "pll_c", "pll_c3", "clk_m" }; @@ -686,9 +677,7 @@ static struct tegra_periph_init_data periph_clks[] = { MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3), MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4), MUX8("sdmmc1", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_9), - MUX8("sdmmc2", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_9), MUX8("sdmmc3", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_9), - MUX8("sdmmc4", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_9), MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la), MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace), MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr), diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 5435d01c636a..9eb1cb14fce1 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -44,6 +44,8 @@ #define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_SOR1 0x410 #define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC4 0x164 #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 @@ -2286,11 +2288,9 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = { [tegra_clk_rtc] = { .dt_id = TEGRA210_CLK_RTC, .present = true }, [tegra_clk_timer] = { .dt_id = TEGRA210_CLK_TIMER, .present = true }, [tegra_clk_uarta_8] = { .dt_id = TEGRA210_CLK_UARTA, .present = true }, - [tegra_clk_sdmmc2_9] = { .dt_id = TEGRA210_CLK_SDMMC2, .present = true }, [tegra_clk_i2s1] = { .dt_id = TEGRA210_CLK_I2S1, .present = true }, [tegra_clk_i2c1] = { .dt_id = TEGRA210_CLK_I2C1, .present = true }, [tegra_clk_sdmmc1_9] = { .dt_id = TEGRA210_CLK_SDMMC1, .present = true }, - [tegra_clk_sdmmc4_9] = { .dt_id = TEGRA210_CLK_SDMMC4, .present = true }, [tegra_clk_pwm] = { .dt_id = TEGRA210_CLK_PWM, .present = true }, [tegra_clk_i2s2] = { .dt_id = TEGRA210_CLK_I2S2, .present = true }, [tegra_clk_usbd] = { .dt_id = TEGRA210_CLK_USBD, .present = true }, @@ -3030,6 +3030,16 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 0, NULL); clks[TEGRA210_CLK_ACLK] = clk; + clk = tegra_clk_register_sdmmc_mux_div("sdmmc2", clk_base, + CLK_SOURCE_SDMMC2, 9, + TEGRA_DIVIDER_ROUND_UP, 0, NULL); + clks[TEGRA210_CLK_SDMMC2] = clk; + + clk = tegra_clk_register_sdmmc_mux_div("sdmmc4", clk_base, + CLK_SOURCE_SDMMC4, 15, + TEGRA_DIVIDER_ROUND_UP, 0, NULL); + clks[TEGRA210_CLK_SDMMC4] = clk; + for (i = 0; i < ARRAY_SIZE(tegra210_periph); i++) { struct tegra_periph_init_data *init = &tegra210_periph[i]; struct clk **clkp; From 0316c018c5a84d4e0b43123057adada3cddb3e00 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Jul 2018 17:37:35 +0900 Subject: [PATCH 74/85] clk: uniphier: add NAND 200MHz clock The Denali NAND controller IP needs three clocks: - clk: controller core clock - clk_x: bus interface clock - ecc_clk: clock at which ECC circuitry is run Currently, only the first one (50MHz) is provided. The rest of the two clock ports must be connected to the 200MHz clock line. Add this. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 4f5ff9fa11fd..a582446735b7 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -29,18 +29,20 @@ UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 10), \ UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 15) -/* Denali driver requires clk_x rate (clk: 50MHz, clk_x & ecc_clk: 200MHz) */ #define UNIPHIER_LD4_SYS_CLK_NAND(idx) \ - UNIPHIER_CLK_FACTOR("nand-200m", -1, "spll", 1, 8), \ - UNIPHIER_CLK_GATE("nand", (idx), "nand-200m", 0x2104, 2) + UNIPHIER_CLK_FACTOR("nand-50m", -1, "spll", 1, 32), \ + UNIPHIER_CLK_GATE("nand", (idx), "nand-50m", 0x2104, 2) #define UNIPHIER_PRO5_SYS_CLK_NAND(idx) \ - UNIPHIER_CLK_FACTOR("nand-200m", -1, "spll", 1, 12), \ - UNIPHIER_CLK_GATE("nand", (idx), "nand-200m", 0x2104, 2) + UNIPHIER_CLK_FACTOR("nand-50m", -1, "spll", 1, 48), \ + UNIPHIER_CLK_GATE("nand", (idx), "nand-50m", 0x2104, 2) #define UNIPHIER_LD11_SYS_CLK_NAND(idx) \ - UNIPHIER_CLK_FACTOR("nand-200m", -1, "spll", 1, 10), \ - UNIPHIER_CLK_GATE("nand", (idx), "nand-200m", 0x210c, 0) + UNIPHIER_CLK_FACTOR("nand-50m", -1, "spll", 1, 40), \ + UNIPHIER_CLK_GATE("nand", (idx), "nand-50m", 0x210c, 0) + +#define UNIPHIER_SYS_CLK_NAND_4X(idx) \ + UNIPHIER_CLK_FACTOR("nand-4x", (idx), "nand", 4, 1) #define UNIPHIER_LD11_SYS_CLK_EMMC(idx) \ UNIPHIER_CLK_GATE("emmc", (idx), NULL, 0x210c, 2) @@ -94,6 +96,7 @@ const struct uniphier_clk_data uniphier_ld4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ @@ -109,6 +112,7 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32), UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), UNIPHIER_PRO4_SYS_CLK_ETHER(6), @@ -131,6 +135,7 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 20), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), UNIPHIER_LD4_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, UNIPHIER_CLK_FACTOR("usb2", -1, "upll", 1, 12), UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* Ether, HSC, MIO */ @@ -144,6 +149,7 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_PRO5_SYS_CLK_SD, UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC */ UNIPHIER_PRO4_SYS_CLK_GIO(12), /* PCIe, USB3 */ @@ -159,6 +165,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 27), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_PRO5_SYS_CLK_SD, UNIPHIER_PRO4_SYS_CLK_ETHER(6), UNIPHIER_LD4_SYS_CLK_STDMAC(8), /* HSC, RLE */ @@ -181,6 +188,7 @@ const struct uniphier_clk_data uniphier_ld11_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), UNIPHIER_LD11_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD11_SYS_CLK_EMMC(4), /* Index 5 reserved for eMMC PHY */ UNIPHIER_LD11_SYS_CLK_ETHER(6), @@ -214,6 +222,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), UNIPHIER_LD11_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD11_SYS_CLK_EMMC(4), /* Index 5 reserved for eMMC PHY */ UNIPHIER_LD20_SYS_CLK_SD, @@ -256,6 +265,7 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), UNIPHIER_LD20_SYS_CLK_SD, UNIPHIER_LD11_SYS_CLK_NAND(2), + UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD11_SYS_CLK_EMMC(4), UNIPHIER_CLK_GATE("ether0", 6, NULL, 0x210c, 9), UNIPHIER_CLK_GATE("ether1", 7, NULL, 0x210c, 10), From 9d222574ef72216bd8332708750bbe743db9bea3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Jul 2018 17:37:36 +0900 Subject: [PATCH 75/85] clk: uniphier: add more USB3 PHY clocks Add USB3 PHY clocks where missing. Use fixed-factor clocks for those without gating. For clarification, prefix clock names with 'ss' or 'hs'. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-sys.c | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index a582446735b7..1c5a998e6c21 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -122,6 +122,9 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_GIO(12), /* Ether, SATA, USB3 */ UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), + UNIPHIER_CLK_FACTOR("usb30-hsphy0", 16, "upll", 1, 12), + UNIPHIER_CLK_FACTOR("usb30-ssphy0", 17, "ref", 1, 1), + UNIPHIER_CLK_FACTOR("usb31-ssphy0", 20, "ref", 1, 1), UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 18), UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x2104, 19), UNIPHIER_PRO4_SYS_CLK_AIO(40), @@ -173,8 +176,11 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { UNIPHIER_PRO4_SYS_CLK_USB3(14, 0), UNIPHIER_PRO4_SYS_CLK_USB3(15, 1), /* The document mentions 0x2104 bit 18, but not functional */ - UNIPHIER_CLK_GATE("usb30-phy", 16, NULL, 0x2104, 19), - UNIPHIER_CLK_GATE("usb31-phy", 20, NULL, 0x2104, 20), + UNIPHIER_CLK_GATE("usb30-hsphy0", 16, NULL, 0x2104, 19), + UNIPHIER_CLK_FACTOR("usb30-ssphy0", 17, "ref", 1, 1), + UNIPHIER_CLK_FACTOR("usb30-ssphy1", 18, "ref", 1, 1), + UNIPHIER_CLK_GATE("usb31-hsphy0", 20, NULL, 0x2104, 20), + UNIPHIER_CLK_FACTOR("usb31-ssphy0", 21, "ref", 1, 1), UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x2104, 22), UNIPHIER_PRO5_SYS_CLK_AIO(40), { /* sentinel */ } @@ -235,8 +241,10 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { * We do not use bit 15 here. */ UNIPHIER_CLK_GATE("usb30", 14, NULL, 0x210c, 14), - UNIPHIER_CLK_GATE("usb30-phy0", 16, NULL, 0x210c, 12), - UNIPHIER_CLK_GATE("usb30-phy1", 17, NULL, 0x210c, 13), + UNIPHIER_CLK_GATE("usb30-hsphy0", 16, NULL, 0x210c, 12), + UNIPHIER_CLK_GATE("usb30-hsphy1", 17, NULL, 0x210c, 13), + UNIPHIER_CLK_FACTOR("usb30-ssphy0", 18, "ref", 1, 1), + UNIPHIER_CLK_FACTOR("usb30-ssphy1", 19, "ref", 1, 1), UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 4), UNIPHIER_LD11_SYS_CLK_AIO(40), UNIPHIER_LD11_SYS_CLK_EVEA(41), @@ -272,11 +280,11 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_CLK_GATE("usb30", 12, NULL, 0x210c, 4), /* =GIO0 */ UNIPHIER_CLK_GATE("usb31-0", 13, NULL, 0x210c, 5), /* =GIO1 */ UNIPHIER_CLK_GATE("usb31-1", 14, NULL, 0x210c, 6), /* =GIO1-1 */ - UNIPHIER_CLK_GATE("usb30-phy0", 16, NULL, 0x210c, 16), - UNIPHIER_CLK_GATE("usb30-phy1", 17, NULL, 0x210c, 18), - UNIPHIER_CLK_GATE("usb30-phy2", 18, NULL, 0x210c, 20), - UNIPHIER_CLK_GATE("usb31-phy0", 20, NULL, 0x210c, 17), - UNIPHIER_CLK_GATE("usb31-phy1", 21, NULL, 0x210c, 19), + UNIPHIER_CLK_GATE("usb30-hsphy0", 16, NULL, 0x210c, 16), + UNIPHIER_CLK_GATE("usb30-ssphy0", 17, NULL, 0x210c, 18), + UNIPHIER_CLK_GATE("usb30-ssphy1", 18, NULL, 0x210c, 20), + UNIPHIER_CLK_GATE("usb31-hsphy0", 20, NULL, 0x210c, 17), + UNIPHIER_CLK_GATE("usb31-ssphy0", 21, NULL, 0x210c, 19), UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 3), UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x210c, 7), UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x210c, 8), From ff388ee3651642d7fdc837b4434a1c7d80b243e4 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Thu, 19 Jul 2018 14:23:48 +0900 Subject: [PATCH 76/85] clk: uniphier: add clock frequency support for SPI Add clock control for SPI controller on UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-peri.c | 9 +++++++++ drivers/clk/uniphier/clk-uniphier-sys.c | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/clk/uniphier/clk-uniphier-peri.c b/drivers/clk/uniphier/clk-uniphier-peri.c index 521c80e9a06f..89b3ac378b3f 100644 --- a/drivers/clk/uniphier/clk-uniphier-peri.c +++ b/drivers/clk/uniphier/clk-uniphier-peri.c @@ -27,6 +27,12 @@ #define UNIPHIER_PERI_CLK_FI2C(idx, ch) \ UNIPHIER_CLK_GATE("i2c" #ch, (idx), "i2c", 0x24, 24 + (ch)) +#define UNIPHIER_PERI_CLK_SCSSI(idx) \ + UNIPHIER_CLK_GATE("scssi", (idx), "spi", 0x20, 17) + +#define UNIPHIER_PERI_CLK_MCSSI(idx) \ + UNIPHIER_CLK_GATE("mcssi", (idx), "spi", 0x24, 14) + const struct uniphier_clk_data uniphier_ld4_peri_clk_data[] = { UNIPHIER_PERI_CLK_UART(0, 0), UNIPHIER_PERI_CLK_UART(1, 1), @@ -38,6 +44,7 @@ const struct uniphier_clk_data uniphier_ld4_peri_clk_data[] = { UNIPHIER_PERI_CLK_I2C(6, 2), UNIPHIER_PERI_CLK_I2C(7, 3), UNIPHIER_PERI_CLK_I2C(8, 4), + UNIPHIER_PERI_CLK_SCSSI(11), { /* sentinel */ } }; @@ -53,5 +60,7 @@ const struct uniphier_clk_data uniphier_pro4_peri_clk_data[] = { UNIPHIER_PERI_CLK_FI2C(8, 4), UNIPHIER_PERI_CLK_FI2C(9, 5), UNIPHIER_PERI_CLK_FI2C(10, 6), + UNIPHIER_PERI_CLK_SCSSI(11), + UNIPHIER_PERI_CLK_MCSSI(12), { /* sentinel */ } }; diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 1c5a998e6c21..2bb5a8570adc 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -95,6 +95,7 @@ const struct uniphier_clk_data uniphier_ld4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 5625, 512), /* 270 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 16), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 32), UNIPHIER_LD4_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, @@ -111,6 +112,7 @@ const struct uniphier_clk_data uniphier_pro4_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("gpll", -1, "ref", 10, 1), /* 250 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "a2pll", 1, 8), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 32), + UNIPHIER_CLK_FACTOR("spi", 1, "spll", 1, 32), UNIPHIER_LD4_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, @@ -137,6 +139,7 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vpll27a", -1, "ref", 270, 25), /* 270 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 20), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 32), UNIPHIER_LD4_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD4_SYS_CLK_SD, @@ -151,6 +154,7 @@ const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("dapll2", -1, "dapll1", 144, 125), /* 2949.12 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_PRO5_SYS_CLK_SD, @@ -167,6 +171,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("spll", -1, "ref", 96, 1), /* 2400 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 27), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_PRO5_SYS_CLK_SD, @@ -193,6 +198,7 @@ const struct uniphier_clk_data uniphier_ld11_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vspll", -1, "ref", 80, 1), /* 2000 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 40), UNIPHIER_LD11_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD11_SYS_CLK_EMMC(4), @@ -227,6 +233,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("vppll", -1, "ref", 504, 5), /* 2520 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 40), UNIPHIER_LD11_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), UNIPHIER_LD11_SYS_CLK_EMMC(4), @@ -271,6 +278,7 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("s2pll", -1, "ref", 88, 1), /* IPP: 2400 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 34), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 40), + UNIPHIER_CLK_FACTOR("spi", -1, "spll", 1, 40), UNIPHIER_LD20_SYS_CLK_SD, UNIPHIER_LD11_SYS_CLK_NAND(2), UNIPHIER_SYS_CLK_NAND_4X(3), From d017c1f16a798397ebc79be57f7a5e5ea788f837 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Thu, 19 Jul 2018 11:06:45 +0200 Subject: [PATCH 77/85] clk: actions: Add missing REGMAP_MMIO dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add REGMAP_MMIO as dependency to avoid undefined reference to regmap symbols. Fixes: d85d20053e19 ("clk: actions: Add S900 SoC clock support") Signed-off-by: Saravanan Sekar Reviewed-by: Andreas Färber Reviewed-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig index 8854adb37847..39491154abbf 100644 --- a/drivers/clk/actions/Kconfig +++ b/drivers/clk/actions/Kconfig @@ -1,6 +1,7 @@ config CLK_ACTIONS bool "Clock driver for Actions Semi SoCs" depends on ARCH_ACTIONS || COMPILE_TEST + select REGMAP_MMIO default ARCH_ACTIONS if CLK_ACTIONS From d0e45d686a3ef18a20d4eac6675b76d3656c4727 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Thu, 19 Jul 2018 11:06:46 +0200 Subject: [PATCH 78/85] dt-bindings: clock: Add S700 support for Actions Semi Soc's Add clock bindings constants for action S700 Maintain common clock dt-bindings for Actions Semi SoC's S700 and S900. Signed-off-by: Parthiban Nallathambi Signed-off-by: Saravanan Sekar Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- ...tions,s900-cmu.txt => actions,owl-cmu.txt} | 20 +-- include/dt-bindings/clock/actions,s700-cmu.h | 118 ++++++++++++++++++ 2 files changed, 129 insertions(+), 9 deletions(-) rename Documentation/devicetree/bindings/clock/{actions,s900-cmu.txt => actions,owl-cmu.txt} (68%) create mode 100644 include/dt-bindings/clock/actions,s700-cmu.h diff --git a/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt similarity index 68% rename from Documentation/devicetree/bindings/clock/actions,s900-cmu.txt rename to Documentation/devicetree/bindings/clock/actions,owl-cmu.txt index 93e4fb827cd6..d1e60d297387 100644 --- a/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt +++ b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt @@ -1,12 +1,14 @@ -* Actions S900 Clock Management Unit (CMU) +* Actions Semi Owl Clock Management Unit (CMU) -The Actions S900 clock management unit generates and supplies clock to various -controllers within the SoC. The clock binding described here is applicable to -S900 SoC. +The Actions Semi Owl Clock Management Unit generates and supplies clock +to various controllers within the SoC. The clock binding described here is +applicable to S900 and S700 SoC's. Required Properties: -- compatible: should be "actions,s900-cmu" +- compatible: should be one of the following, + "actions,s900-cmu" + "actions,s700-cmu" - reg: physical base address of the controller and length of memory mapped region. - clocks: Reference to the parent clocks ("hosc", "losc") @@ -15,16 +17,16 @@ Required Properties: Each clock is assigned an identifier, and client nodes can use this identifier to specify the clock which they consume. -All available clocks are defined as preprocessor macros in -dt-bindings/clock/actions,s900-cmu.h header and can be used in device -tree sources. +All available clocks are defined as preprocessor macros in corresponding +dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be +used in device tree sources. External clocks: The hosc clock used as input for the plls is generated outside the SoC. It is expected that it is defined using standard clock bindings as "hosc". -Actions S900 CMU also requires one more clock: +Actions Semi S900 CMU also requires one more clock: - "losc" - internal low frequency oscillator Example: Clock Management Unit node: diff --git a/include/dt-bindings/clock/actions,s700-cmu.h b/include/dt-bindings/clock/actions,s700-cmu.h new file mode 100644 index 000000000000..3e1942996724 --- /dev/null +++ b/include/dt-bindings/clock/actions,s700-cmu.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Device Tree binding constants for Actions Semi S700 Clock Management Unit + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu + * + * Author: Pathiban Nallathambi + * Author: Saravanan Sekar + */ + +#ifndef __DT_BINDINGS_CLOCK_S700_H +#define __DT_BINDINGS_CLOCK_S700_H + +#define CLK_NONE 0 + +/* pll clocks */ +#define CLK_CORE_PLL 1 +#define CLK_DEV_PLL 2 +#define CLK_DDR_PLL 3 +#define CLK_NAND_PLL 4 +#define CLK_DISPLAY_PLL 5 +#define CLK_TVOUT_PLL 6 +#define CLK_CVBS_PLL 7 +#define CLK_AUDIO_PLL 8 +#define CLK_ETHERNET_PLL 9 + +/* system clock */ +#define CLK_CPU 10 +#define CLK_DEV 11 +#define CLK_AHB 12 +#define CLK_APB 13 +#define CLK_DMAC 14 +#define CLK_NOC0_CLK_MUX 15 +#define CLK_NOC1_CLK_MUX 16 +#define CLK_HP_CLK_MUX 17 +#define CLK_HP_CLK_DIV 18 +#define CLK_NOC1_CLK_DIV 19 +#define CLK_NOC0 20 +#define CLK_NOC1 21 +#define CLK_SENOR_SRC 22 + +/* peripheral device clock */ +#define CLK_GPIO 23 +#define CLK_TIMER 24 +#define CLK_DSI 25 +#define CLK_CSI 26 +#define CLK_SI 27 +#define CLK_DE 28 +#define CLK_HDE 29 +#define CLK_VDE 30 +#define CLK_VCE 31 +#define CLK_NAND 32 +#define CLK_SD0 33 +#define CLK_SD1 34 +#define CLK_SD2 35 + +#define CLK_UART0 36 +#define CLK_UART1 37 +#define CLK_UART2 38 +#define CLK_UART3 39 +#define CLK_UART4 40 +#define CLK_UART5 41 +#define CLK_UART6 42 + +#define CLK_PWM0 43 +#define CLK_PWM1 44 +#define CLK_PWM2 45 +#define CLK_PWM3 46 +#define CLK_PWM4 47 +#define CLK_PWM5 48 +#define CLK_GPU3D 49 + +#define CLK_I2C0 50 +#define CLK_I2C1 51 +#define CLK_I2C2 52 +#define CLK_I2C3 53 + +#define CLK_SPI0 54 +#define CLK_SPI1 55 +#define CLK_SPI2 56 +#define CLK_SPI3 57 + +#define CLK_USB3_480MPLL0 58 +#define CLK_USB3_480MPHY0 59 +#define CLK_USB3_5GPHY 60 +#define CLK_USB3_CCE 61 +#define CLK_USB3_MAC 62 + +#define CLK_LCD 63 +#define CLK_HDMI_AUDIO 64 +#define CLK_I2SRX 65 +#define CLK_I2STX 66 + +#define CLK_SENSOR0 67 +#define CLK_SENSOR1 68 + +#define CLK_HDMI_DEV 69 + +#define CLK_ETHERNET 70 +#define CLK_RMII_REF 71 + +#define CLK_USB2H0_PLLEN 72 +#define CLK_USB2H0_PHY 73 +#define CLK_USB2H0_CCE 74 +#define CLK_USB2H1_PLLEN 75 +#define CLK_USB2H1_PHY 76 +#define CLK_USB2H1_CCE 77 + +#define CLK_TVOUT 78 + +#define CLK_THERMAL_SENSOR 79 + +#define CLK_IRC_SWITCH 80 +#define CLK_PCM1 81 +#define CLK_NR_CLKS (CLK_PCM1 + 1) + +#endif /* __DT_BINDINGS_CLOCK_S700_H */ From d47317ca4ade1a9a1c69c596defb273f29e263b3 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Thu, 19 Jul 2018 11:06:47 +0200 Subject: [PATCH 79/85] clk: actions: Add S700 SoC clock support Add Actions Semi S700 SoC clock support Signed-off-by: Parthiban Nallathambi Signed-off-by: Saravanan Sekar Reviewed-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/Kconfig | 6 + drivers/clk/actions/Makefile | 1 + drivers/clk/actions/owl-s700.c | 606 +++++++++++++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 drivers/clk/actions/owl-s700.c diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig index 39491154abbf..dc38c85a4833 100644 --- a/drivers/clk/actions/Kconfig +++ b/drivers/clk/actions/Kconfig @@ -8,8 +8,14 @@ if CLK_ACTIONS # SoC Drivers +config CLK_OWL_S700 + bool "Support for the Actions Semi OWL S700 clocks" + depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST + default ARM64 && ARCH_ACTIONS + config CLK_OWL_S900 bool "Support for the Actions Semi OWL S900 clocks" depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST default ARM64 && ARCH_ACTIONS + endif diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile index 76e431434d10..78c17d56f991 100644 --- a/drivers/clk/actions/Makefile +++ b/drivers/clk/actions/Makefile @@ -9,4 +9,5 @@ clk-owl-y += owl-composite.o clk-owl-y += owl-pll.o # SoC support +obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c new file mode 100644 index 000000000000..5e9531392ee5 --- /dev/null +++ b/drivers/clk/actions/owl-s700.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Actions Semi S700 clock driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu + * + * Author: Pathiban Nallathambi + * Author: Saravanan Sekar + */ + +#include +#include + +#include "owl-common.h" +#include "owl-composite.h" +#include "owl-divider.h" +#include "owl-factor.h" +#include "owl-fixed-factor.h" +#include "owl-gate.h" +#include "owl-mux.h" +#include "owl-pll.h" + +#include + +#define CMU_COREPLL (0x0000) +#define CMU_DEVPLL (0x0004) +#define CMU_DDRPLL (0x0008) +#define CMU_NANDPLL (0x000C) +#define CMU_DISPLAYPLL (0x0010) +#define CMU_AUDIOPLL (0x0014) +#define CMU_TVOUTPLL (0x0018) +#define CMU_BUSCLK (0x001C) +#define CMU_SENSORCLK (0x0020) +#define CMU_LCDCLK (0x0024) +#define CMU_DSIPLLCLK (0x0028) +#define CMU_CSICLK (0x002C) +#define CMU_DECLK (0x0030) +#define CMU_SICLK (0x0034) +#define CMU_BUSCLK1 (0x0038) +#define CMU_HDECLK (0x003C) +#define CMU_VDECLK (0x0040) +#define CMU_VCECLK (0x0044) +#define CMU_NANDCCLK (0x004C) +#define CMU_SD0CLK (0x0050) +#define CMU_SD1CLK (0x0054) +#define CMU_SD2CLK (0x0058) +#define CMU_UART0CLK (0x005C) +#define CMU_UART1CLK (0x0060) +#define CMU_UART2CLK (0x0064) +#define CMU_UART3CLK (0x0068) +#define CMU_UART4CLK (0x006C) +#define CMU_UART5CLK (0x0070) +#define CMU_UART6CLK (0x0074) +#define CMU_PWM0CLK (0x0078) +#define CMU_PWM1CLK (0x007C) +#define CMU_PWM2CLK (0x0080) +#define CMU_PWM3CLK (0x0084) +#define CMU_PWM4CLK (0x0088) +#define CMU_PWM5CLK (0x008C) +#define CMU_GPU3DCLK (0x0090) +#define CMU_CORECTL (0x009C) +#define CMU_DEVCLKEN0 (0x00A0) +#define CMU_DEVCLKEN1 (0x00A4) +#define CMU_DEVRST0 (0x00A8) +#define CMU_DEVRST1 (0x00AC) +#define CMU_USBPLL (0x00B0) +#define CMU_ETHERNETPLL (0x00B4) +#define CMU_CVBSPLL (0x00B8) +#define CMU_SSTSCLK (0x00C0) + +static struct clk_pll_table clk_audio_pll_table[] = { + {0, 45158400}, {1, 49152000}, + {0, 0}, +}; + +static struct clk_pll_table clk_cvbs_pll_table[] = { + {27, 29 * 12000000}, {28, 30 * 12000000}, {29, 31 * 12000000}, + {30, 32 * 12000000}, {31, 33 * 12000000}, {32, 34 * 12000000}, + {33, 35 * 12000000}, {34, 36 * 12000000}, {35, 37 * 12000000}, + {36, 38 * 12000000}, {37, 39 * 12000000}, {38, 40 * 12000000}, + {39, 41 * 12000000}, {40, 42 * 12000000}, {41, 43 * 12000000}, + {42, 44 * 12000000}, {43, 45 * 12000000}, {0, 0}, +}; + +/* pll clocks */ +static OWL_PLL_NO_PARENT(clk_core_pll, "core_pll", CMU_COREPLL, 12000000, 9, 0, 8, 4, 174, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_dev_pll, "dev_pll", CMU_DEVPLL, 6000000, 8, 0, 8, 8, 126, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_ddr_pll, "ddr_pll", CMU_DDRPLL, 6000000, 8, 0, 8, 2, 180, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_nand_pll, "nand_pll", CMU_NANDPLL, 6000000, 8, 0, 8, 2, 86, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_display_pll, "display_pll", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 2, 140, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_cvbs_pll, "cvbs_pll", CMU_CVBSPLL, 0, 8, 0, 8, 27, 43, clk_cvbs_pll_table, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_audio_pll, "audio_pll", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, clk_audio_pll_table, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT(clk_ethernet_pll, "ethernet_pll", CMU_ETHERNETPLL, 500000000, 0, 0, 0, 0, 0, NULL, CLK_IGNORE_UNUSED); + +static const char *cpu_clk_mux_p[] = {"losc", "hosc", "core_pll", "noc1_clk_div"}; +static const char *dev_clk_p[] = { "hosc", "dev_pll"}; +static const char *noc_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_pll", "cvbs_pll"}; + +static const char *csi_clk_mux_p[] = { "display_pll", "dev_clk"}; +static const char *de_clk_mux_p[] = { "display_pll", "dev_clk"}; +static const char *hde_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_pll"}; +static const char *nand_clk_mux_p[] = { "nand_pll", "display_pll", "dev_clk", "ddr_pll"}; +static const char *sd_clk_mux_p[] = { "dev_clk", "nand_pll", }; +static const char *uart_clk_mux_p[] = { "hosc", "dev_pll"}; +static const char *pwm_clk_mux_p[] = { "losc", "hosc"}; +static const char *gpu_clk_mux_p[] = { "dev_clk", "display_pll", "nand_pll", "ddr_clk", "cvbs_pll"}; +static const char *lcd_clk_mux_p[] = { "display_pll", "dev_clk" }; +static const char *i2s_clk_mux_p[] = { "audio_pll" }; +static const char *sensor_clk_mux_p[] = { "hosc", "si"}; + +/* mux clocks */ +static OWL_MUX(clk_cpu, "cpu_clk", cpu_clk_mux_p, CMU_BUSCLK, 0, 2, CLK_SET_RATE_PARENT); +static OWL_MUX(clk_dev, "dev_clk", dev_clk_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT); +static OWL_MUX(clk_noc0_clk_mux, "noc0_clk_mux", noc_clk_mux_p, CMU_BUSCLK, 4, 3, CLK_SET_RATE_PARENT); +static OWL_MUX(clk_noc1_clk_mux, "noc1_clk_mux", noc_clk_mux_p, CMU_BUSCLK1, 4, 3, CLK_SET_RATE_PARENT); +static OWL_MUX(clk_hp_clk_mux, "hp_clk_mux", noc_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT); + +static struct clk_factor_table sd_factor_table[] = { + /* bit0 ~ 4 */ + {0, 1, 1}, {1, 1, 2}, {2, 1, 3}, {3, 1, 4}, + {4, 1, 5}, {5, 1, 6}, {6, 1, 7}, {7, 1, 8}, + {8, 1, 9}, {9, 1, 10}, {10, 1, 11}, {11, 1, 12}, + {12, 1, 13}, {13, 1, 14}, {14, 1, 15}, {15, 1, 16}, + {16, 1, 17}, {17, 1, 18}, {18, 1, 19}, {19, 1, 20}, + {20, 1, 21}, {21, 1, 22}, {22, 1, 23}, {23, 1, 24}, + {24, 1, 25}, {25, 1, 26}, + + /* bit8: /128 */ + {256, 1, 1 * 128}, {257, 1, 2 * 128}, {258, 1, 3 * 128}, {259, 1, 4 * 128}, + {260, 1, 5 * 128}, {261, 1, 6 * 128}, {262, 1, 7 * 128}, {263, 1, 8 * 128}, + {264, 1, 9 * 128}, {265, 1, 10 * 128}, {266, 1, 11 * 128}, {267, 1, 12 * 128}, + {268, 1, 13 * 128}, {269, 1, 14 * 128}, {270, 1, 15 * 128}, {271, 1, 16 * 128}, + {272, 1, 17 * 128}, {273, 1, 18 * 128}, {274, 1, 19 * 128}, {275, 1, 20 * 128}, + {276, 1, 21 * 128}, {277, 1, 22 * 128}, {278, 1, 23 * 128}, {279, 1, 24 * 128}, + {280, 1, 25 * 128}, {281, 1, 26 * 128}, + + {0, 0}, +}; + +static struct clk_factor_table lcd_factor_table[] = { + /* bit0 ~ 3 */ + {0, 1, 1}, {1, 1, 2}, {2, 1, 3}, {3, 1, 4}, + {4, 1, 5}, {5, 1, 6}, {6, 1, 7}, {7, 1, 8}, + {8, 1, 9}, {9, 1, 10}, {10, 1, 11}, {11, 1, 12}, + + /* bit8: /7 */ + {256, 1, 1 * 7}, {257, 1, 2 * 7}, {258, 1, 3 * 7}, {259, 1, 4 * 7}, + {260, 1, 5 * 7}, {261, 1, 6 * 7}, {262, 1, 7 * 7}, {263, 1, 8 * 7}, + {264, 1, 9 * 7}, {265, 1, 10 * 7}, {266, 1, 11 * 7}, {267, 1, 12 * 7}, + {0, 0}, +}; + +static struct clk_div_table hdmia_div_table[] = { + {0, 1}, {1, 2}, {2, 3}, {3, 4}, + {4, 6}, {5, 8}, {6, 12}, {7, 16}, + {8, 24}, + {0, 0}, +}; + +static struct clk_div_table rmii_div_table[] = { + {0, 4}, {1, 10}, +}; + +/* divider clocks */ +static OWL_DIVIDER(clk_noc0, "noc0_clk", "noc0_clk_mux", CMU_BUSCLK, 16, 2, NULL, 0, 0); +static OWL_DIVIDER(clk_noc1, "noc1_clk", "noc1_clk_mux", CMU_BUSCLK1, 16, 2, NULL, 0, 0); +static OWL_DIVIDER(clk_noc1_clk_div, "noc1_clk_div", "noc1_clk", CMU_BUSCLK1, 20, 1, NULL, 0, 0); +static OWL_DIVIDER(clk_hp_clk_div, "hp_clk_div", "hp_clk_mux", CMU_BUSCLK1, 12, 2, NULL, 0, 0); +static OWL_DIVIDER(clk_ahb, "ahb_clk", "hp_clk_div", CMU_BUSCLK1, 2, 2, NULL, 0, 0); +static OWL_DIVIDER(clk_apb, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0); +static OWL_DIVIDER(clk_sensor0, "sensor0", "sensor_src", CMU_SENSORCLK, 0, 4, NULL, 0, 0); +static OWL_DIVIDER(clk_sensor1, "sensor1", "sensor_src", CMU_SENSORCLK, 8, 4, NULL, 0, 0); +static OWL_DIVIDER(clk_rmii_ref, "rmii_ref", "ethernet_pll", CMU_ETHERNETPLL, 2, 1, rmii_div_table, 0, 0); + +static struct clk_factor_table de_factor_table[] = { + {0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5}, + {4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8}, + {8, 1, 12}, {0, 0, 0}, +}; + +static struct clk_factor_table hde_factor_table[] = { + {0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5}, + {4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8}, + {0, 0, 0}, +}; + +/* gate clocks */ +static OWL_GATE(clk_gpio, "gpio", "apb_clk", CMU_DEVCLKEN1, 25, 0, 0); +static OWL_GATE(clk_dmac, "dmac", "hp_clk_div", CMU_DEVCLKEN0, 17, 0, 0); +static OWL_GATE(clk_timer, "timer", "hosc", CMU_DEVCLKEN1, 22, 0, 0); +static OWL_GATE_NO_PARENT(clk_dsi, "dsi_clk", CMU_DEVCLKEN0, 2, 0, 0); +static OWL_GATE_NO_PARENT(clk_tvout, "tvout_clk", CMU_DEVCLKEN0, 3, 0, 0); +static OWL_GATE_NO_PARENT(clk_hdmi_dev, "hdmi_dev", CMU_DEVCLKEN0, 5, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb3_480mpll0, "usb3_480mpll0", CMU_USBPLL, 3, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb3_480mphy0, "usb3_480mphy0", CMU_USBPLL, 2, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb3_5gphy, "usb3_5gphy", CMU_USBPLL, 1, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb3_cce, "usb3_cce", CMU_DEVCLKEN0, 25, 0, 0); +static OWL_GATE(clk_i2c0, "i2c0", "hosc", CMU_DEVCLKEN1, 0, 0, 0); +static OWL_GATE(clk_i2c1, "i2c1", "hosc", CMU_DEVCLKEN1, 1, 0, 0); +static OWL_GATE(clk_i2c2, "i2c2", "hosc", CMU_DEVCLKEN1, 2, 0, 0); +static OWL_GATE(clk_i2c3, "i2c3", "hosc", CMU_DEVCLKEN1, 3, 0, 0); +static OWL_GATE(clk_spi0, "spi0", "ahb_clk", CMU_DEVCLKEN1, 4, 0, 0); +static OWL_GATE(clk_spi1, "spi1", "ahb_clk", CMU_DEVCLKEN1, 5, 0, 0); +static OWL_GATE(clk_spi2, "spi2", "ahb_clk", CMU_DEVCLKEN1, 6, 0, 0); +static OWL_GATE(clk_spi3, "spi3", "ahb_clk", CMU_DEVCLKEN1, 7, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h0_pllen, "usbh0_pllen", CMU_USBPLL, 12, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h0_phy, "usbh0_phy", CMU_USBPLL, 10, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h0_cce, "usbh0_cce", CMU_DEVCLKEN0, 26, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h1_pllen, "usbh1_pllen", CMU_USBPLL, 13, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h1_phy, "usbh1_phy", CMU_USBPLL, 11, 0, 0); +static OWL_GATE_NO_PARENT(clk_usb2h1_cce, "usbh1_cce", CMU_DEVCLKEN0, 27, 0, 0); +static OWL_GATE_NO_PARENT(clk_irc_switch, "irc_switch", CMU_DEVCLKEN1, 15, 0, 0); + +/* composite clocks */ + +static OWL_COMP_DIV(clk_csi, "csi", csi_clk_mux_p, + OWL_MUX_HW(CMU_CSICLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 13, 0), + OWL_DIVIDER_HW(CMU_CSICLK, 0, 4, 0, NULL), + 0); + +static OWL_COMP_DIV(clk_si, "si", csi_clk_mux_p, + OWL_MUX_HW(CMU_SICLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_DIVIDER_HW(CMU_SICLK, 0, 4, 0, NULL), + 0); + +static OWL_COMP_FACTOR(clk_de, "de", de_clk_mux_p, + OWL_MUX_HW(CMU_DECLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 0, 0), + OWL_FACTOR_HW(CMU_DECLK, 0, 3, 0, de_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_hde, "hde", hde_clk_mux_p, + OWL_MUX_HW(CMU_HDECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 9, 0), + OWL_FACTOR_HW(CMU_HDECLK, 0, 3, 0, hde_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_vde, "vde", hde_clk_mux_p, + OWL_MUX_HW(CMU_VDECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 10, 0), + OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, hde_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_vce, "vce", hde_clk_mux_p, + OWL_MUX_HW(CMU_VCECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0), + OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, hde_factor_table), + 0); + +static OWL_COMP_DIV(clk_nand, "nand", nand_clk_mux_p, + OWL_MUX_HW(CMU_NANDCCLK, 8, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0), + OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 3, 0, NULL), + CLK_SET_RATE_PARENT); + +static OWL_COMP_FACTOR(clk_sd0, "sd0", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD0CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0), + OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_sd1, "sd1", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD1CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 23, 0), + OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_sd2, "sd2", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD2CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 24, 0), + OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_DIV(clk_uart0, "uart0", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART0CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0), + OWL_DIVIDER_HW(CMU_UART0CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart1, "uart1", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART1CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 9, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart2, "uart2", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART2CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 10, 0), + OWL_DIVIDER_HW(CMU_UART2CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart3, "uart3", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART3CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 11, 0), + OWL_DIVIDER_HW(CMU_UART3CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart4, "uart4", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART4CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 12, 0), + OWL_DIVIDER_HW(CMU_UART4CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart5, "uart5", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART5CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 13, 0), + OWL_DIVIDER_HW(CMU_UART5CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_uart6, "uart6", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART6CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0), + OWL_DIVIDER_HW(CMU_UART6CLK, 0, 9, CLK_DIVIDER_ROUND_CLOSEST, NULL), + 0); + +static OWL_COMP_DIV(clk_pwm0, "pwm0", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM0CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 16, 0), + OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 10, 0, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(clk_pwm1, "pwm1", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM1CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 17, 0), + OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(clk_pwm2, "pwm2", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM2CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0), + OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(clk_pwm3, "pwm3", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM3CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0), + OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(clk_pwm4, "pwm4", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM4CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0), + OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(clk_pwm5, "pwm5", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM5CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0), + OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_FACTOR(clk_gpu3d, "gpu3d", gpu_clk_mux_p, + OWL_MUX_HW(CMU_GPU3DCLK, 4, 3), + OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0), + OWL_FACTOR_HW(CMU_GPU3DCLK, 0, 3, 0, hde_factor_table), + 0); + +static OWL_COMP_FACTOR(clk_lcd, "lcd", lcd_clk_mux_p, + OWL_MUX_HW(CMU_LCDCLK, 12, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 1, 0), + OWL_FACTOR_HW(CMU_LCDCLK, 0, 9, 0, lcd_factor_table), + 0); + +static OWL_COMP_DIV(clk_hdmi_audio, "hdmia", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), /*CMU_AUDIOPLL 24,1 unused*/ + OWL_GATE_HW(CMU_DEVCLKEN1, 28, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, hdmia_div_table), + 0); + +static OWL_COMP_DIV(clk_i2srx, "i2srx", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 27, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, hdmia_div_table), + 0); + +static OWL_COMP_DIV(clk_i2stx, "i2stx", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, hdmia_div_table), + 0); + +/* for bluetooth pcm communication */ +static OWL_COMP_FIXED_FACTOR(clk_pcm1, "pcm1", "audio_pll", + OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0), + 1, 2, 0); + +static OWL_COMP_DIV(clk_sensor_src, "sensor_src", sensor_clk_mux_p, + OWL_MUX_HW(CMU_SENSORCLK, 4, 1), + {0}, + OWL_DIVIDER_HW(CMU_SENSORCLK, 5, 2, 0, NULL), + 0); + +static OWL_COMP_FIXED_FACTOR(clk_ethernet, "ethernet", "ethernet_pll", + OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0), + 1, 20, 0); + +static OWL_COMP_DIV_FIXED(clk_thermal_sensor, "thermal_sensor", "hosc", + OWL_GATE_HW(CMU_DEVCLKEN0, 31, 0), + OWL_DIVIDER_HW(CMU_SSTSCLK, 20, 10, 0, NULL), + 0); + +static struct owl_clk_common *s700_clks[] = { + &clk_core_pll.common, + &clk_dev_pll.common, + &clk_ddr_pll.common, + &clk_nand_pll.common, + &clk_display_pll.common, + &clk_cvbs_pll .common, + &clk_audio_pll.common, + &clk_ethernet_pll.common, + &clk_cpu.common, + &clk_dev.common, + &clk_ahb.common, + &clk_apb.common, + &clk_dmac.common, + &clk_noc0_clk_mux.common, + &clk_noc1_clk_mux.common, + &clk_hp_clk_mux.common, + &clk_hp_clk_div.common, + &clk_noc1_clk_div.common, + &clk_noc0.common, + &clk_noc1.common, + &clk_sensor_src.common, + &clk_gpio.common, + &clk_timer.common, + &clk_dsi.common, + &clk_csi.common, + &clk_si.common, + &clk_de.common, + &clk_hde.common, + &clk_vde.common, + &clk_vce.common, + &clk_nand.common, + &clk_sd0.common, + &clk_sd1.common, + &clk_sd2.common, + &clk_uart0.common, + &clk_uart1.common, + &clk_uart2.common, + &clk_uart3.common, + &clk_uart4.common, + &clk_uart5.common, + &clk_uart6.common, + &clk_pwm0.common, + &clk_pwm1.common, + &clk_pwm2.common, + &clk_pwm3.common, + &clk_pwm4.common, + &clk_pwm5.common, + &clk_gpu3d.common, + &clk_i2c0.common, + &clk_i2c1.common, + &clk_i2c2.common, + &clk_i2c3.common, + &clk_spi0.common, + &clk_spi1.common, + &clk_spi2.common, + &clk_spi3.common, + &clk_usb3_480mpll0.common, + &clk_usb3_480mphy0.common, + &clk_usb3_5gphy.common, + &clk_usb3_cce.common, + &clk_lcd.common, + &clk_hdmi_audio.common, + &clk_i2srx.common, + &clk_i2stx.common, + &clk_sensor0.common, + &clk_sensor1.common, + &clk_hdmi_dev.common, + &clk_ethernet.common, + &clk_rmii_ref.common, + &clk_usb2h0_pllen.common, + &clk_usb2h0_phy.common, + &clk_usb2h0_cce.common, + &clk_usb2h1_pllen.common, + &clk_usb2h1_phy.common, + &clk_usb2h1_cce.common, + &clk_tvout.common, + &clk_thermal_sensor.common, + &clk_irc_switch.common, + &clk_pcm1.common, +}; + +static struct clk_hw_onecell_data s700_hw_clks = { + .hws = { + [CLK_CORE_PLL] = &clk_core_pll.common.hw, + [CLK_DEV_PLL] = &clk_dev_pll.common.hw, + [CLK_DDR_PLL] = &clk_ddr_pll.common.hw, + [CLK_NAND_PLL] = &clk_nand_pll.common.hw, + [CLK_DISPLAY_PLL] = &clk_display_pll.common.hw, + [CLK_CVBS_PLL] = &clk_cvbs_pll .common.hw, + [CLK_AUDIO_PLL] = &clk_audio_pll.common.hw, + [CLK_ETHERNET_PLL] = &clk_ethernet_pll.common.hw, + [CLK_CPU] = &clk_cpu.common.hw, + [CLK_DEV] = &clk_dev.common.hw, + [CLK_AHB] = &clk_ahb.common.hw, + [CLK_APB] = &clk_apb.common.hw, + [CLK_DMAC] = &clk_dmac.common.hw, + [CLK_NOC0_CLK_MUX] = &clk_noc0_clk_mux.common.hw, + [CLK_NOC1_CLK_MUX] = &clk_noc1_clk_mux.common.hw, + [CLK_HP_CLK_MUX] = &clk_hp_clk_mux.common.hw, + [CLK_HP_CLK_DIV] = &clk_hp_clk_div.common.hw, + [CLK_NOC1_CLK_DIV] = &clk_noc1_clk_div.common.hw, + [CLK_NOC0] = &clk_noc0.common.hw, + [CLK_NOC1] = &clk_noc1.common.hw, + [CLK_SENOR_SRC] = &clk_sensor_src.common.hw, + [CLK_GPIO] = &clk_gpio.common.hw, + [CLK_TIMER] = &clk_timer.common.hw, + [CLK_DSI] = &clk_dsi.common.hw, + [CLK_CSI] = &clk_csi.common.hw, + [CLK_SI] = &clk_si.common.hw, + [CLK_DE] = &clk_de.common.hw, + [CLK_HDE] = &clk_hde.common.hw, + [CLK_VDE] = &clk_vde.common.hw, + [CLK_VCE] = &clk_vce.common.hw, + [CLK_NAND] = &clk_nand.common.hw, + [CLK_SD0] = &clk_sd0.common.hw, + [CLK_SD1] = &clk_sd1.common.hw, + [CLK_SD2] = &clk_sd2.common.hw, + [CLK_UART0] = &clk_uart0.common.hw, + [CLK_UART1] = &clk_uart1.common.hw, + [CLK_UART2] = &clk_uart2.common.hw, + [CLK_UART3] = &clk_uart3.common.hw, + [CLK_UART4] = &clk_uart4.common.hw, + [CLK_UART5] = &clk_uart5.common.hw, + [CLK_UART6] = &clk_uart6.common.hw, + [CLK_PWM0] = &clk_pwm0.common.hw, + [CLK_PWM1] = &clk_pwm1.common.hw, + [CLK_PWM2] = &clk_pwm2.common.hw, + [CLK_PWM3] = &clk_pwm3.common.hw, + [CLK_PWM4] = &clk_pwm4.common.hw, + [CLK_PWM5] = &clk_pwm5.common.hw, + [CLK_GPU3D] = &clk_gpu3d.common.hw, + [CLK_I2C0] = &clk_i2c0.common.hw, + [CLK_I2C1] = &clk_i2c1.common.hw, + [CLK_I2C2] = &clk_i2c2.common.hw, + [CLK_I2C3] = &clk_i2c3.common.hw, + [CLK_SPI0] = &clk_spi0.common.hw, + [CLK_SPI1] = &clk_spi1.common.hw, + [CLK_SPI2] = &clk_spi2.common.hw, + [CLK_SPI3] = &clk_spi3.common.hw, + [CLK_USB3_480MPLL0] = &clk_usb3_480mpll0.common.hw, + [CLK_USB3_480MPHY0] = &clk_usb3_480mphy0.common.hw, + [CLK_USB3_5GPHY] = &clk_usb3_5gphy.common.hw, + [CLK_USB3_CCE] = &clk_usb3_cce.common.hw, + [CLK_LCD] = &clk_lcd.common.hw, + [CLK_HDMI_AUDIO] = &clk_hdmi_audio.common.hw, + [CLK_I2SRX] = &clk_i2srx.common.hw, + [CLK_I2STX] = &clk_i2stx.common.hw, + [CLK_SENSOR0] = &clk_sensor0.common.hw, + [CLK_SENSOR1] = &clk_sensor1.common.hw, + [CLK_HDMI_DEV] = &clk_hdmi_dev.common.hw, + [CLK_ETHERNET] = &clk_ethernet.common.hw, + [CLK_RMII_REF] = &clk_rmii_ref.common.hw, + [CLK_USB2H0_PLLEN] = &clk_usb2h0_pllen.common.hw, + [CLK_USB2H0_PHY] = &clk_usb2h0_phy.common.hw, + [CLK_USB2H0_CCE] = &clk_usb2h0_cce.common.hw, + [CLK_USB2H1_PLLEN] = &clk_usb2h1_pllen.common.hw, + [CLK_USB2H1_PHY] = &clk_usb2h1_phy.common.hw, + [CLK_USB2H1_CCE] = &clk_usb2h1_cce.common.hw, + [CLK_TVOUT] = &clk_tvout.common.hw, + [CLK_THERMAL_SENSOR] = &clk_thermal_sensor.common.hw, + [CLK_IRC_SWITCH] = &clk_irc_switch.common.hw, + [CLK_PCM1] = &clk_pcm1.common.hw, + }, + .num = CLK_NR_CLKS, +}; + +static const struct owl_clk_desc s700_clk_desc = { + .clks = s700_clks, + .num_clks = ARRAY_SIZE(s700_clks), + + .hw_clks = &s700_hw_clks, +}; + +static int s700_clk_probe(struct platform_device *pdev) +{ + const struct owl_clk_desc *desc; + + desc = &s700_clk_desc; + owl_clk_regmap_init(pdev, desc); + + return owl_clk_probe(&pdev->dev, desc->hw_clks); +} + +static const struct of_device_id s700_clk_of_match[] = { + { .compatible = "actions,s700-cmu", }, + { /* sentinel */ } +}; + +static struct platform_driver s700_clk_driver = { + .probe = s700_clk_probe, + .driver = { + .name = "s700-cmu", + .of_match_table = s700_clk_of_match + }, +}; + +static int __init s700_clk_init(void) +{ + return platform_driver_register(&s700_clk_driver); +} +core_initcall(s700_clk_init); From 96455f734b2f6491b07a9a5b0c94513f0f4c9144 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 18 Jul 2018 21:56:20 +0200 Subject: [PATCH 80/85] clk: samsung: Remove unused mout_user_aclk400_mcuisp_p4x12 variable Remove unused 'mout_user_aclk400_mcuisp_p4x12' variable to fix GCC warning: drivers/clk/samsung/clk-exynos4412-isp.c:40:27: warning: 'mout_user_aclk400_mcuisp_p4x12' defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos4412-isp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index d5f1ccb36300..cfaa057035ad 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -37,8 +37,6 @@ static const unsigned long exynos4x12_clk_isp_save[] __initconst = { E4X12_GATE_ISP1, }; -PNAME(mout_user_aclk400_mcuisp_p4x12) = { "fin_pll", "div_aclk400_mcuisp", }; - static struct samsung_div_clock exynos4x12_isp_div_clks[] = { DIV(CLK_ISP_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3), DIV(CLK_ISP_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3), From 8927c27b32703e28041ae19bf25ea53461be83a1 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 27 Jul 2018 00:27:21 +0200 Subject: [PATCH 81/85] clk: mvebu: armada-37xx-periph: Remove unused var num_parents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building armada-37xx-periph, num_parents isn't used in function clk_pm_cpu_get_parent: drivers/clk/mvebu/armada-37xx-periph.c: In function ‘clk_pm_cpu_get_parent’: drivers/clk/mvebu/armada-37xx-periph.c:419:6: warning: unused variable ‘num_parents’ [-Wunused-variable] int num_parents = clk_hw_get_num_parents(hw); ^~~~~~~~~~~ Remove the declaration of num_parents to dispose the warning. Fixes: 616bf80d381d ("clk: mvebu: armada-37xx-periph: Fix wrong return value in get_parent") Signed-off-by: Anders Roxell Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-37xx-periph.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 5cf0a52b87e8..b841ec3c6d6e 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -418,7 +418,6 @@ static unsigned int armada_3700_pm_dvfs_get_cpu_parent(struct regmap *base) static u8 clk_pm_cpu_get_parent(struct clk_hw *hw) { struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw); - int num_parents = clk_hw_get_num_parents(hw); u32 val; if (armada_3700_pm_dvfs_is_enabled(pm_cpu->nb_pm_base)) { From 81351776c9fbbbd0de1dc1542f30aacfe68efc4e Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 23 Jul 2018 16:24:35 +0530 Subject: [PATCH 82/85] clk: qcom: Add display clock controller driver for SDM845 Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Signed-off-by: Taniya Das [sboyd@kernel.org: Remove CLK_GET_RATE_NOCACHE everywhere] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/dispcc-sdm845.c | 685 +++++++++++++++++++++++++++++++ 3 files changed, 696 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9c3480dcc38a..730057471932 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -245,6 +245,16 @@ config SDM_VIDEOCC_845 Say Y if you want to support video devices and functionality such as video encode and decode. +config SDM_DISPCC_845 + tristate "SDM845 Display Clock Controller" + select SDM_GCC_845 + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDM845 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 762c01137c2f..2b041b2db30a 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000000000000..0cc4909b5dbe --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,685 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_MAIN, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x20d0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x20ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x2108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x2120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x2088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_shared_ops, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x2058, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x2070, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_parent_map_4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_names = disp_cc_parent_names_4, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { + .cmd_rcgr = 0x20a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_3, + .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk_src", + .parent_names = disp_cc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x20b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch disp_cc_mdss_ahb_clk = { + .halt_reg = 0x4004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_axi_clk = { + .halt_reg = 0x4008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_byte0_clk = { + .halt_reg = 0x2028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x20e8, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_clk_src", + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x202c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x202c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte0_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_byte1_clk = { + .halt_reg = 0x2030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x2104, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_div_clk_src", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_clk_src", + }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x2034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_byte1_div_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc0_clk = { + .halt_reg = 0x2038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_esc1_clk = { + .halt_reg = 0x203c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_esc1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_clk = { + .halt_reg = 0x200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_mdp_lut_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_mdp_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x2004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk0_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_branch disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x2008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_pclk1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_pclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rot_clk = { + .halt_reg = 0x2014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rot_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_rot_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0x5004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0x5008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_rscc_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_vsync_clk = { + .halt_reg = 0x2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_vsync_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x3000, + .pd = { + .name = "mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *disp_cc_sdm845_clocks[] = { + [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, + [DISP_CC_MDSS_AXI_CLK] = &disp_cc_mdss_axi_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr, + [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr, + [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr, + [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = + &disp_cc_mdss_byte0_div_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr, + [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr, + [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, + [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = + &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, + [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, + [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, + [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr, + [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr, + [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr, + [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr, + [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, + [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, + [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr, + [DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr, + [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, + [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr, + [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr, + [DISP_CC_PLL0] = &disp_cc_pll0.clkr, +}; + +static const struct qcom_reset_map disp_cc_sdm845_resets[] = { + [DISP_CC_MDSS_RSCC_BCR] = { 0x5000 }, +}; + +static struct gdsc *disp_cc_sdm845_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, +}; + +static const struct regmap_config disp_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x10000, + .fast_io = true, +}; + +static const struct qcom_cc_desc disp_cc_sdm845_desc = { + .config = &disp_cc_sdm845_regmap_config, + .clks = disp_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sdm845_clocks), + .resets = disp_cc_sdm845_resets, + .num_resets = ARRAY_SIZE(disp_cc_sdm845_resets), + .gdscs = disp_cc_sdm845_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sdm845_gdscs), +}; + +static const struct of_device_id disp_cc_sdm845_match_table[] = { + { .compatible = "qcom,sdm845-dispcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table); + +static int disp_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct alpha_pll_config disp_cc_pll0_config = {}; + + regmap = qcom_cc_map(pdev, &disp_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + disp_cc_pll0_config.l = 0x2c; + disp_cc_pll0_config.alpha = 0xcaaa; + + clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + + /* Enable hardware clock gating for DSI and MDP clocks */ + regmap_update_bits(regmap, 0x8000, 0x7f0, 0x7f0); + + return qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap); +} + +static struct platform_driver disp_cc_sdm845_driver = { + .probe = disp_cc_sdm845_probe, + .driver = { + .name = "disp_cc-sdm845", + .of_match_table = disp_cc_sdm845_match_table, + }, +}; + +static int __init disp_cc_sdm845_init(void) +{ + return platform_driver_register(&disp_cc_sdm845_driver); +} +subsys_initcall(disp_cc_sdm845_init); + +static void __exit disp_cc_sdm845_exit(void) +{ + platform_driver_unregister(&disp_cc_sdm845_driver); +} +module_exit(disp_cc_sdm845_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QTI DISPCC SDM845 Driver"); From 7a8655e19bdb3be43f6a3b4768c9b0928a2585fc Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Tue, 31 Jul 2018 11:25:55 +0530 Subject: [PATCH 83/85] clk: scmi: Fix the rounding of clock rate This fix rounds the clock rate properly by using quotient and not remainder in the calculation. This issue was found while testing HDMI in the Juno platform. Fixes: 6d6a1d82eaef7 ("clk: add support for clocks provided by SCMI") Acked-by: Sudeep Holla Signed-off-by: Amit Daniel Kachhap Signed-off-by: Stephen Boyd --- drivers/clk/clk-scmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index bb2a6f2f5516..a985bf5e1ac6 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -38,7 +38,6 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw, static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - int step; u64 fmin, fmax, ftmp; struct scmi_clk *clk = to_scmi_clk(hw); @@ -60,9 +59,9 @@ static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate, ftmp = rate - fmin; ftmp += clk->info->range.step_size - 1; /* to round up */ - step = do_div(ftmp, clk->info->range.step_size); + do_div(ftmp, clk->info->range.step_size); - return step * clk->info->range.step_size + fmin; + return ftmp * clk->info->range.step_size + fmin; } static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, From 67075b3cb8d509642ff09ef3134a3b2d30c45a32 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Jul 2018 07:49:55 +0000 Subject: [PATCH 84/85] clk: cs2000-cp: convert to SPDX identifiers Signed-off-by: Kuninori Morimoto Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index a2f8c42e527a..92bc4aca0f95 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * CS2000 -- CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier * * Copyright (C) 2015 Renesas Electronics Corporation * Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include From 640332d1a089909df08bc9f3e42888a2019c66e2 Mon Sep 17 00:00:00 2001 From: Levin Du Date: Sat, 4 Aug 2018 15:31:02 +0800 Subject: [PATCH 85/85] clk: rockchip: Add pclk_rkpwm_pmu to PMU critical clocks in rk3399 PWM2 is commonly used to control voltage of PWM regulator of VDD_LOG in RK3399. On the Firefly-RK3399 board, PWM2 outputs 40 KHz square wave from power on and the VDD_LOG is about 0.9V. When the kernel boots normally into the system, the PWM2 keeps outputing PWM signal. But the kernel hangs randomly after "Starting kernel ..." line on that board. When it happens, PWM2 outputs high level which causes VDD_LOG drops to 0.4V below the normal operating voltage. By adding "pclk_rkpwm_pmu" to the rk3399_pmucru_critical_clocks array, PWM clock is ensured to be prepared at startup and the PWM2 output is normal. After repeated tests, the early boot hang is gone. This patch works on both Firefly-RK3399 and ROC-RK3399-PC boards. Signed-off-by: Levin Du Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3399.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 2a8634a52856..5a628148f3f0 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1523,6 +1523,7 @@ static const char *const rk3399_pmucru_critical_clocks[] __initconst = { "pclk_pmu_src", "fclk_cm0s_src_pmu", "clk_timer_src_pmu", + "pclk_rkpwm_pmu", }; static void __init rk3399_clk_init(struct device_node *np)