diff options
19 files changed, 3523 insertions, 73 deletions
diff --git a/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml index 3330b2727474..6961a68098f4 100644 --- a/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml +++ b/Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml @@ -8,6 +8,7 @@ title: Samsung ExynosAuto v920 SoC clock controller maintainers: - Sunyeal Hong <sunyeal.hong@samsung.com> + - Shin Son <shin.son@samsung.com> - Chanwoo Choi <cw00.choi@samsung.com> - Krzysztof Kozlowski <krzk@kernel.org> - Sylwester Nawrocki <s.nawrocki@samsung.com> @@ -32,6 +33,9 @@ properties: compatible: enum: - samsung,exynosautov920-cmu-top + - samsung,exynosautov920-cmu-cpucl0 + - samsung,exynosautov920-cmu-cpucl1 + - samsung,exynosautov920-cmu-cpucl2 - samsung,exynosautov920-cmu-peric0 - samsung,exynosautov920-cmu-peric1 - samsung,exynosautov920-cmu-misc @@ -74,6 +78,71 @@ allOf: compatible: contains: enum: + - samsung,exynosautov920-cmu-cpucl0 + + then: + properties: + clocks: + items: + - description: External reference clock (38.4 MHz) + - description: CMU_CPUCL0 SWITCH clock (from CMU_TOP) + - description: CMU_CPUCL0 CLUSTER clock (from CMU_TOP) + - description: CMU_CPUCL0 DBG clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: switch + - const: cluster + - const: dbg + + - if: + properties: + compatible: + contains: + enum: + - samsung,exynosautov920-cmu-cpucl1 + + then: + properties: + clocks: + items: + - description: External reference clock (38.4 MHz) + - description: CMU_CPUCL1 SWITCH clock (from CMU_TOP) + - description: CMU_CPUCL1 CLUSTER clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: switch + - const: cluster + + - if: + properties: + compatible: + contains: + enum: + - samsung,exynosautov920-cmu-cpucl2 + + then: + properties: + clocks: + items: + - description: External reference clock (38.4 MHz) + - description: CMU_CPUCL2 SWITCH clock (from CMU_TOP) + - description: CMU_CPUCL2 CLUSTER clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: switch + - const: cluster + + - if: + properties: + compatible: + contains: + enum: - samsung,exynosautov920-cmu-peric0 - samsung,exynosautov920-cmu-peric1 diff --git a/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml index 59ef41adb539..379ce3e9e391 100644 --- a/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml +++ b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml @@ -11,10 +11,18 @@ maintainers: properties: compatible: - enum: - - sophgo,cv1800-clk - - sophgo,cv1810-clk - - sophgo,sg2000-clk + oneOf: + - enum: + - sophgo,cv1800b-clk + - sophgo,cv1812h-clk + - sophgo,sg2000-clk + - items: + - const: sophgo,sg2002-clk + - const: sophgo,sg2000-clk + - const: sophgo,cv1800-clk + deprecated: true + - const: sophgo,cv1810-clk + deprecated: true reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/clock/sophgo,sg2044-clk.yaml b/Documentation/devicetree/bindings/clock/sophgo,sg2044-clk.yaml new file mode 100644 index 000000000000..272e58bdb62c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sophgo,sg2044-clk.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/sophgo,sg2044-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2044 Clock Controller + +maintainers: + - Inochi Amaoto <inochiama@gmail.com> + +description: | + The Sophgo SG2044 clock controller requires an external oscillator + as input clock. + + All available clocks are defined as preprocessor macros in + include/dt-bindings/clock/sophgo,sg2044-clk.h + +properties: + compatible: + const: sophgo,sg2044-clk + + reg: + maxItems: 1 + + clocks: + items: + - description: fpll0 + - description: fpll1 + - description: fpll2 + - description: dpll0 + - description: dpll1 + - description: dpll2 + - description: dpll3 + - description: dpll4 + - description: dpll5 + - description: dpll6 + - description: dpll7 + - description: mpll0 + - description: mpll1 + - description: mpll2 + - description: mpll3 + - description: mpll4 + - description: mpll5 + + clock-names: + items: + - const: fpll0 + - const: fpll1 + - const: fpll2 + - const: dpll0 + - const: dpll1 + - const: dpll2 + - const: dpll3 + - const: dpll4 + - const: dpll5 + - const: dpll6 + - const: dpll7 + - const: mpll0 + - const: mpll1 + - const: mpll2 + - const: mpll3 + - const: mpll4 + - const: mpll5 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/sophgo,sg2044-pll.h> + + clock-controller@50002000 { + compatible = "sophgo,sg2044-clk"; + reg = <0x50002000 0x1000>; + #clock-cells = <1>; + clocks = <&syscon CLK_FPLL0>, <&syscon CLK_FPLL1>, + <&syscon CLK_FPLL2>, <&syscon CLK_DPLL0>, + <&syscon CLK_DPLL1>, <&syscon CLK_DPLL2>, + <&syscon CLK_DPLL3>, <&syscon CLK_DPLL4>, + <&syscon CLK_DPLL5>, <&syscon CLK_DPLL6>, + <&syscon CLK_DPLL7>, <&syscon CLK_MPLL0>, + <&syscon CLK_MPLL1>, <&syscon CLK_MPLL2>, + <&syscon CLK_MPLL3>, <&syscon CLK_MPLL4>, + <&syscon CLK_MPLL5>; + clock-names = "fpll0", "fpll1", "fpll2", "dpll0", + "dpll1", "dpll2", "dpll3", "dpll4", + "dpll5", "dpll6", "dpll7", "mpll0", + "mpll1", "mpll2", "mpll3", "mpll4", + "mpll5"; + }; diff --git a/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml b/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml index 0129bd0ba4b3..9d058c00ab3d 100644 --- a/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml +++ b/Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml @@ -8,7 +8,8 @@ title: T-HEAD TH1520 AP sub-system clock controller description: | The T-HEAD TH1520 AP sub-system clock controller configures the - CPU, DPU, GMAC and TEE PLLs. + CPU, DPU, GMAC and TEE PLLs. Additionally the VO subsystem configures + the clock gates for the HDMI, MIPI and the GPU. SoC reference manual https://openbeagle.org/beaglev-ahead/beaglev-ahead/-/blob/main/docs/TH1520%20System%20User%20Manual.pdf @@ -20,14 +21,24 @@ maintainers: properties: compatible: - const: thead,th1520-clk-ap + enum: + - thead,th1520-clk-ap + - thead,th1520-clk-vo reg: maxItems: 1 clocks: items: - - description: main oscillator (24MHz) + - description: | + One input clock: + - For "thead,th1520-clk-ap": the clock input must be the 24 MHz + main oscillator. + - For "thead,th1520-clk-vo": the clock input must be the VIDEO_PLL, + which is configured by the AP clock controller. According to the + TH1520 manual, VIDEO_PLL is a Silicon Creations Sigma-Delta PLL + (integer PLL) typically running at 792 MHz (FOUTPOSTDIV), with + a maximum FOUTVCO of 2376 MHz. "#clock-cells": const: 1 diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2044-top-syscon.yaml b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2044-top-syscon.yaml new file mode 100644 index 000000000000..a82cc3cae576 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2044-top-syscon.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/sophgo/sophgo,sg2044-top-syscon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo SG2044 SoC TOP system controller + +maintainers: + - Inochi Amaoto <inochiama@gmail.com> + +description: + The Sophgo SG2044 TOP system controller is a hardware block grouping + multiple small functions, such as clocks and some other internal + function. + +properties: + compatible: + items: + - const: sophgo,sg2044-top-syscon + - const: syscon + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + '#clock-cells': + const: 1 + description: + See <dt-bindings/clock/sophgo,sg2044-pll.h> for valid clock. + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + syscon@50000000 { + compatible = "sophgo,sg2044-top-syscon", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + clocks = <&osc>; + }; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 374c26e5d9fd..cc5c1644c41c 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1269,6 +1269,45 @@ static const struct samsung_cpu_clock exynos4412_cpu_clks[] __initconst = { CPUCLK_LAYOUT_E4210, e4412_armclk_d), }; +static const struct samsung_cmu_info cmu_info_exynos4 __initconst = { + .mux_clks = exynos4_mux_clks, + .nr_mux_clks = ARRAY_SIZE(exynos4_mux_clks), + .div_clks = exynos4_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos4_div_clks), + .gate_clks = exynos4_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos4_gate_clks), + .fixed_factor_clks = exynos4_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(exynos4_fixed_factor_clks), + .fixed_clks = exynos4_fixed_rate_clks, + .nr_fixed_clks = ARRAY_SIZE(exynos4_fixed_rate_clks), +}; + +static const struct samsung_cmu_info cmu_info_exynos4210 __initconst = { + .mux_clks = exynos4210_mux_clks, + .nr_mux_clks = ARRAY_SIZE(exynos4210_mux_clks), + .div_clks = exynos4210_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos4210_div_clks), + .gate_clks = exynos4210_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos4210_gate_clks), + .fixed_factor_clks = exynos4210_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(exynos4210_fixed_factor_clks), + .fixed_clks = exynos4210_fixed_rate_clks, + .nr_fixed_clks = ARRAY_SIZE(exynos4210_fixed_rate_clks), + .cpu_clks = exynos4210_cpu_clks, + .nr_cpu_clks = ARRAY_SIZE(exynos4210_cpu_clks), +}; + +static const struct samsung_cmu_info cmu_info_exynos4x12 __initconst = { + .mux_clks = exynos4x12_mux_clks, + .nr_mux_clks = ARRAY_SIZE(exynos4x12_mux_clks), + .div_clks = exynos4x12_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos4x12_div_clks), + .gate_clks = exynos4x12_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos4x12_gate_clks), + .fixed_factor_clks = exynos4x12_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(exynos4x12_fixed_factor_clks), +}; + /* register exynos4 clocks */ static void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc soc) @@ -1322,41 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4x12_plls)); } - samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_clks, - ARRAY_SIZE(exynos4_fixed_rate_clks)); - samsung_clk_register_mux(ctx, exynos4_mux_clks, - ARRAY_SIZE(exynos4_mux_clks)); - samsung_clk_register_div(ctx, exynos4_div_clks, - ARRAY_SIZE(exynos4_div_clks)); - samsung_clk_register_gate(ctx, exynos4_gate_clks, - ARRAY_SIZE(exynos4_gate_clks)); - samsung_clk_register_fixed_factor(ctx, exynos4_fixed_factor_clks, - ARRAY_SIZE(exynos4_fixed_factor_clks)); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4); if (exynos4_soc == EXYNOS4210) { - samsung_clk_register_fixed_rate(ctx, exynos4210_fixed_rate_clks, - ARRAY_SIZE(exynos4210_fixed_rate_clks)); - samsung_clk_register_mux(ctx, exynos4210_mux_clks, - ARRAY_SIZE(exynos4210_mux_clks)); - samsung_clk_register_div(ctx, exynos4210_div_clks, - ARRAY_SIZE(exynos4210_div_clks)); - samsung_clk_register_gate(ctx, exynos4210_gate_clks, - ARRAY_SIZE(exynos4210_gate_clks)); - samsung_clk_register_fixed_factor(ctx, - exynos4210_fixed_factor_clks, - ARRAY_SIZE(exynos4210_fixed_factor_clks)); - samsung_clk_register_cpu(ctx, exynos4210_cpu_clks, - ARRAY_SIZE(exynos4210_cpu_clks)); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210); } else { - samsung_clk_register_mux(ctx, exynos4x12_mux_clks, - ARRAY_SIZE(exynos4x12_mux_clks)); - samsung_clk_register_div(ctx, exynos4x12_div_clks, - ARRAY_SIZE(exynos4x12_div_clks)); - samsung_clk_register_gate(ctx, exynos4x12_gate_clks, - ARRAY_SIZE(exynos4x12_gate_clks)); - samsung_clk_register_fixed_factor(ctx, - exynos4x12_fixed_factor_clks, - ARRAY_SIZE(exynos4x12_fixed_factor_clks)); + samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12); if (soc == EXYNOS4412) samsung_clk_register_cpu(ctx, exynos4412_cpu_clks, ARRAY_SIZE(exynos4412_cpu_clks)); diff --git a/drivers/clk/samsung/clk-exynosautov920.c b/drivers/clk/samsung/clk-exynosautov920.c index dc8d4240f6de..da4afe8ac2ab 100644 --- a/drivers/clk/samsung/clk-exynosautov920.c +++ b/drivers/clk/samsung/clk-exynosautov920.c @@ -18,6 +18,9 @@ /* NOTE: Must be equal to the last clock ID increased by one */ #define CLKS_NR_TOP (DOUT_CLKCMU_TAA_NOC + 1) +#define CLKS_NR_CPUCL0 (CLK_DOUT_CPUCL0_NOCP + 1) +#define CLKS_NR_CPUCL1 (CLK_DOUT_CPUCL1_NOCP + 1) +#define CLKS_NR_CPUCL2 (CLK_DOUT_CPUCL2_NOCP + 1) #define CLKS_NR_PERIC0 (CLK_DOUT_PERIC0_I3C + 1) #define CLKS_NR_PERIC1 (CLK_DOUT_PERIC1_I3C + 1) #define CLKS_NR_MISC (CLK_DOUT_MISC_OSC_DIV2 + 1) @@ -1005,6 +1008,339 @@ static void __init exynosautov920_cmu_top_init(struct device_node *np) CLK_OF_DECLARE(exynosautov920_cmu_top, "samsung,exynosautov920-cmu-top", exynosautov920_cmu_top_init); +/* ---- CMU_CPUCL0 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_CPUCL0 (0x1EC00000) */ +#define PLL_LOCKTIME_PLL_CPUCL0 0x0000 +#define PLL_CON0_PLL_CPUCL0 0x0100 +#define PLL_CON1_PLL_CPUCL0 0x0104 +#define PLL_CON3_PLL_CPUCL0 0x010c +#define PLL_CON0_MUX_CLKCMU_CPUCL0_CLUSTER_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER 0x0610 +#define PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER 0x0620 + +#define CLK_CON_MUX_MUX_CLK_CPUCL0_CLUSTER 0x1000 +#define CLK_CON_MUX_MUX_CLK_CPUCL0_CORE 0x1004 + +#define CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK 0x1800 +#define CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK 0x1804 +#define CLK_CON_DIV_DIV_CLK_CLUSTER0_MPCLK 0x1808 +#define CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLK 0x180c +#define CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK 0x1810 +#define CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_NOC 0x181c +#define CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_PCLKDBG 0x1820 +#define CLK_CON_DIV_DIV_CLK_CPUCL0_NOCP 0x1824 + +static const unsigned long cpucl0_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_CPUCL0, + PLL_CON0_PLL_CPUCL0, + PLL_CON1_PLL_CPUCL0, + PLL_CON3_PLL_CPUCL0, + PLL_CON0_MUX_CLKCMU_CPUCL0_CLUSTER_USER, + PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER, + PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER, + CLK_CON_MUX_MUX_CLK_CPUCL0_CLUSTER, + CLK_CON_MUX_MUX_CLK_CPUCL0_CORE, + CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK, + CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER0_MPCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK, + CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_NOC, + CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_PCLKDBG, + CLK_CON_DIV_DIV_CLK_CPUCL0_NOCP, +}; + +/* List of parent clocks for Muxes in CMU_CPUCL0 */ +PNAME(mout_pll_cpucl0_p) = { "oscclk", "fout_cpucl0_pll" }; +PNAME(mout_cpucl0_cluster_user_p) = { "oscclk", "dout_clkcmu_cpucl0_cluster" }; +PNAME(mout_cpucl0_dbg_user_p) = { "oscclk", "dout_clkcmu_cpucl0_dbg" }; +PNAME(mout_cpucl0_switch_user_p) = { "oscclk", "dout_clkcmu_cpucl0_switch" }; +PNAME(mout_cpucl0_cluster_p) = { "oscclk", "mout_cpucl0_cluster_user", + "mout_cpucl0_switch_user"}; +PNAME(mout_cpucl0_core_p) = { "oscclk", "mout_pll_cpucl0", + "mout_cpucl0_switch_user"}; + +static const struct samsung_pll_rate_table cpu_pll_rates[] __initconst = { + PLL_35XX_RATE(38400000U, 2400000000U, 250, 4, 0), + PLL_35XX_RATE(38400000U, 2304000000U, 240, 4, 0), + PLL_35XX_RATE(38400000U, 2208000000U, 230, 4, 0), + PLL_35XX_RATE(38400000U, 2112000000U, 220, 4, 0), + PLL_35XX_RATE(38400000U, 2016000000U, 210, 4, 0), + PLL_35XX_RATE(38400000U, 1824000000U, 190, 4, 0), + PLL_35XX_RATE(38400000U, 1680000000U, 175, 4, 0), + PLL_35XX_RATE(38400000U, 1344000000U, 140, 4, 0), + PLL_35XX_RATE(38400000U, 1152000000U, 120, 4, 0), + PLL_35XX_RATE(38400000U, 576000000U, 120, 4, 1), + PLL_35XX_RATE(38400000U, 288000000U, 120, 4, 2), +}; + +static const struct samsung_pll_clock cpucl0_pll_clks[] __initconst = { + /* CMU_CPUCL0_PURECLKCOMP */ + PLL(pll_531x, CLK_FOUT_CPUCL0_PLL, "fout_cpucl0_pll", "oscclk", + PLL_LOCKTIME_PLL_CPUCL0, PLL_CON3_PLL_CPUCL0, cpu_pll_rates), +}; + +static const struct samsung_mux_clock cpucl0_mux_clks[] __initconst = { + MUX(CLK_MOUT_PLL_CPUCL0, "mout_pll_cpucl0", mout_pll_cpucl0_p, + PLL_CON0_PLL_CPUCL0, 4, 1), + MUX(CLK_MOUT_CPUCL0_CLUSTER_USER, "mout_cpucl0_cluster_user", mout_cpucl0_cluster_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL0_CLUSTER_USER, 4, 1), + MUX(CLK_MOUT_CPUCL0_DBG_USER, "mout_cpucl0_dbg_user", mout_cpucl0_dbg_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL0_DBG_USER, 4, 1), + MUX(CLK_MOUT_CPUCL0_SWITCH_USER, "mout_cpucl0_switch_user", mout_cpucl0_switch_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL0_SWITCH_USER, 4, 1), + MUX(CLK_MOUT_CPUCL0_CLUSTER, "mout_cpucl0_cluster", mout_cpucl0_cluster_p, + CLK_CON_MUX_MUX_CLK_CPUCL0_CLUSTER, 0, 2), + MUX(CLK_MOUT_CPUCL0_CORE, "mout_cpucl0_core", mout_cpucl0_core_p, + CLK_CON_MUX_MUX_CLK_CPUCL0_CORE, 0, 2), +}; + +static const struct samsung_div_clock cpucl0_div_clks[] __initconst = { + DIV(CLK_DOUT_CLUSTER0_ACLK, "dout_cluster0_aclk", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER0_ACLK, 0, 4), + DIV(CLK_DOUT_CLUSTER0_ATCLK, "dout_cluster0_atclk", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER0_ATCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER0_MPCLK, "dout_cluster0_mpclk", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER0_MPCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER0_PCLK, "dout_cluster0_pclk", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER0_PCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER0_PERIPHCLK, "dout_cluster0_periphclk", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER0_PERIPHCLK, 0, 4), + DIV(CLK_DOUT_CPUCL0_DBG_NOC, "dout_cpucl0_dbg_noc", + "mout_cpucl0_dbg_user", CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_NOC, 0, 3), + DIV(CLK_DOUT_CPUCL0_DBG_PCLKDBG, "dout_cpucl0_dbg_pclkdbg", + "mout_cpucl0_dbg_user", CLK_CON_DIV_DIV_CLK_CPUCL0_DBG_PCLKDBG, 0, 3), + DIV(CLK_DOUT_CPUCL0_NOCP, "dout_cpucl0_nocp", + "mout_cpucl0_cluster", CLK_CON_DIV_DIV_CLK_CPUCL0_NOCP, 0, 4), +}; + +static const struct samsung_cmu_info cpucl0_cmu_info __initconst = { + .pll_clks = cpucl0_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cpucl0_pll_clks), + .mux_clks = cpucl0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cpucl0_mux_clks), + .div_clks = cpucl0_div_clks, + .nr_div_clks = ARRAY_SIZE(cpucl0_div_clks), + .nr_clk_ids = CLKS_NR_CPUCL0, + .clk_regs = cpucl0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cpucl0_clk_regs), + .clk_name = "cpucl0", +}; + +static void __init exynosautov920_cmu_cpucl0_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &cpucl0_cmu_info); +} + +/* Register CMU_CPUCL0 early, as CPU clocks should be available ASAP */ +CLK_OF_DECLARE(exynosautov920_cmu_cpucl0, "samsung,exynosautov920-cmu-cpucl0", + exynosautov920_cmu_cpucl0_init); + +/* ---- CMU_CPUCL1 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_CPUCL1 (0x1ED00000) */ +#define PLL_LOCKTIME_PLL_CPUCL1 0x0000 +#define PLL_CON0_PLL_CPUCL1 0x0100 +#define PLL_CON1_PLL_CPUCL1 0x0104 +#define PLL_CON3_PLL_CPUCL1 0x010c +#define PLL_CON0_MUX_CLKCMU_CPUCL1_CLUSTER_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER 0x0610 + +#define CLK_CON_MUX_MUX_CLK_CPUCL1_CLUSTER 0x1000 +#define CLK_CON_MUX_MUX_CLK_CPUCL1_CORE 0x1004 + +#define CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK 0x1800 +#define CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK 0x1804 +#define CLK_CON_DIV_DIV_CLK_CLUSTER1_MPCLK 0x1808 +#define CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLK 0x180c +#define CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK 0x1810 +#define CLK_CON_DIV_DIV_CLK_CPUCL1_NOCP 0x181c + +static const unsigned long cpucl1_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_CPUCL1, + PLL_CON0_PLL_CPUCL1, + PLL_CON1_PLL_CPUCL1, + PLL_CON3_PLL_CPUCL1, + PLL_CON0_MUX_CLKCMU_CPUCL1_CLUSTER_USER, + PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER, + CLK_CON_MUX_MUX_CLK_CPUCL1_CLUSTER, + CLK_CON_MUX_MUX_CLK_CPUCL1_CORE, + CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK, + CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER1_MPCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK, + CLK_CON_DIV_DIV_CLK_CPUCL1_NOCP, +}; + +/* List of parent clocks for Muxes in CMU_CPUCL1 */ +PNAME(mout_pll_cpucl1_p) = { "oscclk", "fout_cpucl1_pll" }; +PNAME(mout_cpucl1_cluster_user_p) = { "oscclk", "dout_clkcmu_cpucl1_cluster" }; +PNAME(mout_cpucl1_switch_user_p) = { "oscclk", "dout_clkcmu_cpucl1_switch" }; +PNAME(mout_cpucl1_cluster_p) = { "oscclk", "mout_cpucl1_cluster_user", + "mout_cpucl1_switch_user"}; +PNAME(mout_cpucl1_core_p) = { "oscclk", "mout_pll_cpucl1", + "mout_cpucl1_switch_user"}; + +static const struct samsung_pll_clock cpucl1_pll_clks[] __initconst = { + /* CMU_CPUCL1_PURECLKCOMP */ + PLL(pll_531x, CLK_FOUT_CPUCL1_PLL, "fout_cpucl1_pll", "oscclk", + PLL_LOCKTIME_PLL_CPUCL1, PLL_CON3_PLL_CPUCL1, cpu_pll_rates), +}; + +static const struct samsung_mux_clock cpucl1_mux_clks[] __initconst = { + MUX(CLK_MOUT_PLL_CPUCL1, "mout_pll_cpucl1", mout_pll_cpucl1_p, + PLL_CON0_PLL_CPUCL1, 4, 1), + MUX(CLK_MOUT_CPUCL1_CLUSTER_USER, "mout_cpucl1_cluster_user", mout_cpucl1_cluster_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL1_CLUSTER_USER, 4, 1), + MUX(CLK_MOUT_CPUCL1_SWITCH_USER, "mout_cpucl1_switch_user", mout_cpucl1_switch_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL1_SWITCH_USER, 4, 1), + MUX(CLK_MOUT_CPUCL1_CLUSTER, "mout_cpucl1_cluster", mout_cpucl1_cluster_p, + CLK_CON_MUX_MUX_CLK_CPUCL1_CLUSTER, 0, 2), + MUX(CLK_MOUT_CPUCL1_CORE, "mout_cpucl1_core", mout_cpucl1_core_p, + CLK_CON_MUX_MUX_CLK_CPUCL1_CORE, 0, 2), +}; + +static const struct samsung_div_clock cpucl1_div_clks[] __initconst = { + DIV(CLK_DOUT_CLUSTER1_ACLK, "dout_cluster1_aclk", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER1_ACLK, 0, 4), + DIV(CLK_DOUT_CLUSTER1_ATCLK, "dout_cluster1_atclk", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER1_ATCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER1_MPCLK, "dout_cluster1_mpclk", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER1_MPCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER1_PCLK, "dout_cluster1_pclk", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER1_PCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER1_PERIPHCLK, "dout_cluster1_periphclk", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER1_PERIPHCLK, 0, 4), + DIV(CLK_DOUT_CPUCL1_NOCP, "dout_cpucl1_nocp", + "mout_cpucl1_cluster", CLK_CON_DIV_DIV_CLK_CPUCL1_NOCP, 0, 4), +}; + +static const struct samsung_cmu_info cpucl1_cmu_info __initconst = { + .pll_clks = cpucl1_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cpucl1_pll_clks), + .mux_clks = cpucl1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cpucl1_mux_clks), + .div_clks = cpucl1_div_clks, + .nr_div_clks = ARRAY_SIZE(cpucl1_div_clks), + .nr_clk_ids = CLKS_NR_CPUCL1, + .clk_regs = cpucl1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cpucl1_clk_regs), + .clk_name = "cpucl1", +}; + +static void __init exynosautov920_cmu_cpucl1_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &cpucl1_cmu_info); +} + +/* Register CMU_CPUCL1 early, as CPU clocks should be available ASAP */ +CLK_OF_DECLARE(exynosautov920_cmu_cpucl1, "samsung,exynosautov920-cmu-cpucl1", + exynosautov920_cmu_cpucl1_init); + +/* ---- CMU_CPUCL2 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_CPUCL2 (0x1EE00000) */ +#define PLL_LOCKTIME_PLL_CPUCL2 0x0000 +#define PLL_CON0_PLL_CPUCL2 0x0100 +#define PLL_CON1_PLL_CPUCL2 0x0104 +#define PLL_CON3_PLL_CPUCL2 0x010c +#define PLL_CON0_MUX_CLKCMU_CPUCL2_CLUSTER_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_CPUCL2_SWITCH_USER 0x0610 + +#define CLK_CON_MUX_MUX_CLK_CPUCL2_CLUSTER 0x1000 +#define CLK_CON_MUX_MUX_CLK_CPUCL2_CORE 0x1004 + +#define CLK_CON_DIV_DIV_CLK_CLUSTER2_ACLK 0x1800 +#define CLK_CON_DIV_DIV_CLK_CLUSTER2_ATCLK 0x1804 +#define CLK_CON_DIV_DIV_CLK_CLUSTER2_MPCLK 0x1808 +#define CLK_CON_DIV_DIV_CLK_CLUSTER2_PCLK 0x180c +#define CLK_CON_DIV_DIV_CLK_CLUSTER2_PERIPHCLK 0x1810 +#define CLK_CON_DIV_DIV_CLK_CPUCL2_NOCP 0x181c + +static const unsigned long cpucl2_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_CPUCL2, + PLL_CON0_PLL_CPUCL2, + PLL_CON1_PLL_CPUCL2, + PLL_CON3_PLL_CPUCL2, + PLL_CON0_MUX_CLKCMU_CPUCL2_CLUSTER_USER, + PLL_CON0_MUX_CLKCMU_CPUCL2_SWITCH_USER, + CLK_CON_MUX_MUX_CLK_CPUCL2_CLUSTER, + CLK_CON_MUX_MUX_CLK_CPUCL2_CORE, + CLK_CON_DIV_DIV_CLK_CLUSTER2_ACLK, + CLK_CON_DIV_DIV_CLK_CLUSTER2_ATCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER2_MPCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER2_PCLK, + CLK_CON_DIV_DIV_CLK_CLUSTER2_PERIPHCLK, + CLK_CON_DIV_DIV_CLK_CPUCL2_NOCP, +}; + +/* List of parent clocks for Muxes in CMU_CPUCL2 */ +PNAME(mout_pll_cpucl2_p) = { "oscclk", "fout_cpucl2_pll" }; +PNAME(mout_cpucl2_cluster_user_p) = { "oscclk", "dout_clkcmu_cpucl2_cluster" }; +PNAME(mout_cpucl2_switch_user_p) = { "oscclk", "dout_clkcmu_cpucl2_switch" }; +PNAME(mout_cpucl2_cluster_p) = { "oscclk", "mout_cpucl2_cluster_user", + "mout_cpucl2_switch_user"}; +PNAME(mout_cpucl2_core_p) = { "oscclk", "mout_pll_cpucl2", + "mout_cpucl2_switch_user"}; + +static const struct samsung_pll_clock cpucl2_pll_clks[] __initconst = { + /* CMU_CPUCL2_PURECLKCOMP */ + PLL(pll_531x, CLK_FOUT_CPUCL2_PLL, "fout_cpucl2_pll", "oscclk", + PLL_LOCKTIME_PLL_CPUCL2, PLL_CON3_PLL_CPUCL2, cpu_pll_rates), +}; + +static const struct samsung_mux_clock cpucl2_mux_clks[] __initconst = { + MUX(CLK_MOUT_PLL_CPUCL2, "mout_pll_cpucl2", mout_pll_cpucl2_p, + PLL_CON0_PLL_CPUCL2, 4, 1), + MUX(CLK_MOUT_CPUCL2_CLUSTER_USER, "mout_cpucl2_cluster_user", mout_cpucl2_cluster_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL2_CLUSTER_USER, 4, 1), + MUX(CLK_MOUT_CPUCL2_SWITCH_USER, "mout_cpucl2_switch_user", mout_cpucl2_switch_user_p, + PLL_CON0_MUX_CLKCMU_CPUCL2_SWITCH_USER, 4, 1), + MUX(CLK_MOUT_CPUCL2_CLUSTER, "mout_cpucl2_cluster", mout_cpucl2_cluster_p, + CLK_CON_MUX_MUX_CLK_CPUCL2_CLUSTER, 0, 2), + MUX(CLK_MOUT_CPUCL2_CORE, "mout_cpucl2_core", mout_cpucl2_core_p, + CLK_CON_MUX_MUX_CLK_CPUCL2_CORE, 0, 2), +}; + +static const struct samsung_div_clock cpucl2_div_clks[] __initconst = { + DIV(CLK_DOUT_CLUSTER2_ACLK, "dout_cluster2_aclk", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER2_ACLK, 0, 4), + DIV(CLK_DOUT_CLUSTER2_ATCLK, "dout_cluster2_atclk", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER2_ATCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER2_MPCLK, "dout_cluster2_mpclk", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER2_MPCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER2_PCLK, "dout_cluster2_pclk", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER2_PCLK, 0, 4), + DIV(CLK_DOUT_CLUSTER2_PERIPHCLK, "dout_cluster2_periphclk", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CLUSTER2_PERIPHCLK, 0, 4), + DIV(CLK_DOUT_CPUCL2_NOCP, "dout_cpucl2_nocp", + "mout_cpucl2_cluster", CLK_CON_DIV_DIV_CLK_CPUCL2_NOCP, 0, 4), +}; + +static const struct samsung_cmu_info cpucl2_cmu_info __initconst = { + .pll_clks = cpucl2_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cpucl2_pll_clks), + .mux_clks = cpucl2_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cpucl2_mux_clks), + .div_clks = cpucl2_div_clks, + .nr_div_clks = ARRAY_SIZE(cpucl2_div_clks), + .nr_clk_ids = CLKS_NR_CPUCL2, + .clk_regs = cpucl2_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cpucl2_clk_regs), + .clk_name = "cpucl2", +}; + +static void __init exynosautov920_cmu_cpucl2_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &cpucl2_cmu_info); +} + +/* Register CMU_CPUCL2 early, as CPU clocks should be available ASAP */ +CLK_OF_DECLARE(exynosautov920_cmu_cpucl2, "samsung,exynosautov920-cmu-cpucl2", + exynosautov920_cmu_cpucl2_init); + /* ---- CMU_PERIC0 --------------------------------------------------------- */ /* Register Offset definitions for CMU_PERIC0 (0x10800000) */ @@ -1393,7 +1729,7 @@ static const unsigned long hsi1_clk_regs[] __initconst = { /* List of parent clocks for Muxes in CMU_HSI1 */ PNAME(mout_hsi1_mmc_card_user_p) = {"oscclk", "dout_clkcmu_hsi1_mmc_card"}; PNAME(mout_hsi1_noc_user_p) = { "oscclk", "dout_clkcmu_hsi1_noc" }; -PNAME(mout_hsi1_usbdrd_user_p) = { "oscclk", "mout_clkcmu_hsi1_usbdrd" }; +PNAME(mout_hsi1_usbdrd_user_p) = { "oscclk", "dout_clkcmu_hsi1_usbdrd" }; PNAME(mout_hsi1_usbdrd_p) = { "dout_tcxo_div2", "mout_hsi1_usbdrd_user" }; static const struct samsung_mux_clock hsi1_mux_clks[] __initconst = { diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c index 1d82737befd3..a88c212bda12 100644 --- a/drivers/clk/socfpga/clk-pll-s10.c +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -83,9 +83,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, unsigned long parent_rate) { struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); - unsigned long mdiv; - unsigned long refdiv; - unsigned long reg; + u32 mdiv; + u32 refdiv; + u32 reg; unsigned long long vco_freq; /* read VCO1 reg for numerator and denominator */ diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index 9dcc1b2d2cc0..03a96139a576 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -39,9 +39,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, unsigned long parent_rate) { struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); - unsigned long divf, divq, reg; + u32 divf, divq, reg; unsigned long long vco_freq; - unsigned long bypass; + u32 bypass; reg = readl(socfpgaclk->hw.reg); bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS); diff --git a/drivers/clk/sophgo/Kconfig b/drivers/clk/sophgo/Kconfig index 8b1367e3a95e..e14e802f28bf 100644 --- a/drivers/clk/sophgo/Kconfig +++ b/drivers/clk/sophgo/Kconfig @@ -37,3 +37,22 @@ config CLK_SOPHGO_SG2042_RPGATE This clock IP depends on SG2042 Clock Generator because it uses clock from Clock Generator IP as input. This driver provides Gate function for RP. + +config CLK_SOPHGO_SG2044 + tristate "Sophgo SG2044 clock controller support" + depends on ARCH_SOPHGO || COMPILE_TEST + help + This driver supports the clock controller on the Sophgo SG2044 + SoC. This controller requires mulitple PLL clock as input. + This clock control provides PLL clocks and common clock function + for various IPs on the SoC. + +config CLK_SOPHGO_SG2044_PLL + tristate "Sophgo SG2044 PLL clock controller support" + depends on ARCH_SOPHGO || COMPILE_TEST + select MFD_SYSCON + select REGMAP_MMIO + help + This driver supports the PLL clock controller on the Sophgo + SG2044 SoC. This controller requires 25M oscillator as input. + This clock control provides PLL clocks on the SoC. diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile index 53506845a044..26b2fd121582 100644 --- a/drivers/clk/sophgo/Makefile +++ b/drivers/clk/sophgo/Makefile @@ -9,3 +9,5 @@ clk-sophgo-cv1800-y += clk-cv18xx-pll.o obj-$(CONFIG_CLK_SOPHGO_SG2042_CLKGEN) += clk-sg2042-clkgen.o obj-$(CONFIG_CLK_SOPHGO_SG2042_PLL) += clk-sg2042-pll.o obj-$(CONFIG_CLK_SOPHGO_SG2042_RPGATE) += clk-sg2042-rpgate.o +obj-$(CONFIG_CLK_SOPHGO_SG2044) += clk-sg2044.o +obj-$(CONFIG_CLK_SOPHGO_SG2044_PLL) += clk-sg2044-pll.o diff --git a/drivers/clk/sophgo/clk-cv1800.c b/drivers/clk/sophgo/clk-cv1800.c index e0c4dc347579..a4116ac1adcb 100644 --- a/drivers/clk/sophgo/clk-cv1800.c +++ b/drivers/clk/sophgo/clk-cv1800.c @@ -1519,7 +1519,9 @@ static int cv1800_clk_probe(struct platform_device *pdev) static const struct of_device_id cv1800_clk_ids[] = { { .compatible = "sophgo,cv1800-clk", .data = &cv1800_desc }, + { .compatible = "sophgo,cv1800b-clk", .data = &cv1800_desc }, { .compatible = "sophgo,cv1810-clk", .data = &cv1810_desc }, + { .compatible = "sophgo,cv1812h-clk", .data = &cv1810_desc }, { .compatible = "sophgo,sg2000-clk", .data = &sg2000_desc }, { } }; diff --git a/drivers/clk/sophgo/clk-sg2044-pll.c b/drivers/clk/sophgo/clk-sg2044-pll.c new file mode 100644 index 000000000000..94c0f519ba6d --- /dev/null +++ b/drivers/clk/sophgo/clk-sg2044-pll.c @@ -0,0 +1,628 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2044 PLL clock controller driver + * + * Copyright (C) 2025 Inochi Amaoto <inochiama@gmail.com> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/math64.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/spinlock.h> + +#include <dt-bindings/clock/sophgo,sg2044-pll.h> + +/* Low Control part */ +#define PLL_VCOSEL_MASK GENMASK(17, 16) + +/* High Control part */ +#define PLL_FBDIV_MASK GENMASK(11, 0) +#define PLL_REFDIV_MASK GENMASK(17, 12) +#define PLL_POSTDIV1_MASK GENMASK(20, 18) +#define PLL_POSTDIV2_MASK GENMASK(23, 21) + +#define PLL_CALIBRATE_EN BIT(24) +#define PLL_CALIBRATE_MASK GENMASK(29, 27) +#define PLL_CALIBRATE_DEFAULT FIELD_PREP(PLL_CALIBRATE_MASK, 2) +#define PLL_UPDATE_EN BIT(30) + +#define PLL_HIGH_CTRL_MASK \ + (PLL_FBDIV_MASK | PLL_REFDIV_MASK | \ + PLL_POSTDIV1_MASK | PLL_POSTDIV2_MASK | \ + PLL_CALIBRATE_EN | PLL_CALIBRATE_MASK | \ + PLL_UPDATE_EN) + +#define PLL_HIGH_CTRL_OFFSET 4 + +#define PLL_VCOSEL_1G6 0x2 +#define PLL_VCOSEL_2G4 0x3 + +#define PLL_LIMIT_FOUTVCO 0 +#define PLL_LIMIT_FOUT 1 +#define PLL_LIMIT_REFDIV 2 +#define PLL_LIMIT_FBDIV 3 +#define PLL_LIMIT_POSTDIV1 4 +#define PLL_LIMIT_POSTDIV2 5 + +#define for_each_pll_limit_range(_var, _limit) \ + for (_var = (_limit)->min; _var <= (_limit)->max; _var++) + +struct sg2044_pll_limit { + u64 min; + u64 max; +}; + +struct sg2044_pll_internal { + u32 ctrl_offset; + u32 status_offset; + u32 enable_offset; + + u8 status_lock_bit; + u8 status_updating_bit; + u8 enable_bit; + + const struct sg2044_pll_limit *limits; +}; + +struct sg2044_clk_common { + struct clk_hw hw; + struct regmap *regmap; + spinlock_t *lock; + unsigned int id; +}; + +struct sg2044_pll { + struct sg2044_clk_common common; + struct sg2044_pll_internal pll; + unsigned int syscon_offset; +}; + +struct sg2044_pll_desc_data { + struct sg2044_clk_common * const *pll; + u16 num_pll; +}; + +#define SG2044_SYSCON_PLL_OFFSET 0x98 + +struct sg2044_pll_ctrl { + spinlock_t lock; + struct clk_hw_onecell_data data; +}; + +#define hw_to_sg2044_clk_common(_hw) \ + container_of((_hw), struct sg2044_clk_common, hw) + +static inline bool sg2044_clk_fit_limit(u64 value, + const struct sg2044_pll_limit *limit) +{ + return value >= limit->min && value <= limit->max; +} + +static inline struct sg2044_pll *hw_to_sg2044_pll(struct clk_hw *hw) +{ + return container_of(hw_to_sg2044_clk_common(hw), + struct sg2044_pll, common); +} + +static unsigned long sg2044_pll_calc_vco_rate(unsigned long parent_rate, + unsigned long refdiv, + unsigned long fbdiv) +{ + u64 numerator = parent_rate * fbdiv; + + return div64_ul(numerator, refdiv); +} + +static unsigned long sg2044_pll_calc_rate(unsigned long parent_rate, + unsigned long refdiv, + unsigned long fbdiv, + unsigned long postdiv1, + unsigned long postdiv2) +{ + u64 numerator, denominator; + + numerator = parent_rate * fbdiv; + denominator = refdiv * (postdiv1 + 1) * (postdiv2 + 1); + + return div64_u64(numerator, denominator); +} + +static unsigned long sg2044_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sg2044_pll *pll = hw_to_sg2044_pll(hw); + u32 value; + int ret; + + ret = regmap_read(pll->common.regmap, + pll->syscon_offset + pll->pll.ctrl_offset + PLL_HIGH_CTRL_OFFSET, + &value); + if (ret < 0) + return 0; + + return sg2044_pll_calc_rate(parent_rate, + FIELD_GET(PLL_REFDIV_MASK, value), + FIELD_GET(PLL_FBDIV_MASK, value), + FIELD_GET(PLL_POSTDIV1_MASK, value), + FIELD_GET(PLL_POSTDIV2_MASK, value)); +} + +static bool pll_is_better_rate(unsigned long target, unsigned long now, + unsigned long best) +{ + return abs_diff(target, now) < abs_diff(target, best); +} + +static int sg2042_pll_compute_postdiv(const struct sg2044_pll_limit *limits, + unsigned long target, + unsigned long parent_rate, + unsigned int refdiv, + unsigned int fbdiv, + unsigned int *postdiv1, + unsigned int *postdiv2) +{ + unsigned int div1, div2; + unsigned long tmp, best_rate = 0; + unsigned int best_div1 = 0, best_div2 = 0; + + for_each_pll_limit_range(div2, &limits[PLL_LIMIT_POSTDIV2]) { + for_each_pll_limit_range(div1, &limits[PLL_LIMIT_POSTDIV1]) { + tmp = sg2044_pll_calc_rate(parent_rate, + refdiv, fbdiv, + div1, div2); + + if (tmp > target) + continue; + + if (pll_is_better_rate(target, tmp, best_rate)) { + best_div1 = div1; + best_div2 = div2; + best_rate = tmp; + + if (tmp == target) + goto find; + } + } + } + +find: + if (best_rate) { + *postdiv1 = best_div1; + *postdiv2 = best_div2; + return 0; + } + + return -EINVAL; +} + +static int sg2044_compute_pll_setting(const struct sg2044_pll_limit *limits, + unsigned long req_rate, + unsigned long parent_rate, + unsigned int *value) +{ + unsigned int refdiv, fbdiv, postdiv1, postdiv2; + unsigned int best_refdiv, best_fbdiv, best_postdiv1, best_postdiv2; + unsigned long tmp, best_rate = 0; + int ret; + + for_each_pll_limit_range(fbdiv, &limits[PLL_LIMIT_FBDIV]) { + for_each_pll_limit_range(refdiv, &limits[PLL_LIMIT_REFDIV]) { + u64 vco = sg2044_pll_calc_vco_rate(parent_rate, + refdiv, fbdiv); + if (!sg2044_clk_fit_limit(vco, &limits[PLL_LIMIT_FOUTVCO])) + continue; + + ret = sg2042_pll_compute_postdiv(limits, + req_rate, parent_rate, + refdiv, fbdiv, + &postdiv1, &postdiv2); + if (ret) + continue; + + tmp = sg2044_pll_calc_rate(parent_rate, + refdiv, fbdiv, + postdiv1, postdiv2); + + if (pll_is_better_rate(req_rate, tmp, best_rate)) { + best_refdiv = refdiv; + best_fbdiv = fbdiv; + best_postdiv1 = postdiv1; + best_postdiv2 = postdiv2; + best_rate = tmp; + + if (tmp == req_rate) + goto find; + } + } + } + +find: + if (best_rate) { + *value = FIELD_PREP(PLL_REFDIV_MASK, best_refdiv) | + FIELD_PREP(PLL_FBDIV_MASK, best_fbdiv) | + FIELD_PREP(PLL_POSTDIV1_MASK, best_postdiv1) | + FIELD_PREP(PLL_POSTDIV2_MASK, best_postdiv2); + return 0; + } + + return -EINVAL; +} + +static int sg2044_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct sg2044_pll *pll = hw_to_sg2044_pll(hw); + unsigned int value; + u64 target; + int ret; + + target = clamp(req->rate, pll->pll.limits[PLL_LIMIT_FOUT].min, + pll->pll.limits[PLL_LIMIT_FOUT].max); + + ret = sg2044_compute_pll_setting(pll->pll.limits, target, + req->best_parent_rate, &value); + if (ret < 0) + return ret; + + req->rate = sg2044_pll_calc_rate(req->best_parent_rate, + FIELD_GET(PLL_REFDIV_MASK, value), + FIELD_GET(PLL_FBDIV_MASK, value), + FIELD_GET(PLL_POSTDIV1_MASK, value), + FIELD_GET(PLL_POSTDIV2_MASK, value)); + + return 0; +} + +static int sg2044_pll_poll_update(struct sg2044_pll *pll) +{ + int ret; + unsigned int value; + + ret = regmap_read_poll_timeout_atomic(pll->common.regmap, + pll->syscon_offset + pll->pll.status_offset, + value, + (value & BIT(pll->pll.status_lock_bit)), + 1, 100000); + if (ret) + return ret; + + return regmap_read_poll_timeout_atomic(pll->common.regmap, + pll->syscon_offset + pll->pll.status_offset, + value, + (!(value & BIT(pll->pll.status_updating_bit))), + 1, 100000); +} + +static int sg2044_pll_enable(struct sg2044_pll *pll, bool en) +{ + if (en) { + if (sg2044_pll_poll_update(pll) < 0) + pr_warn("%s: fail to lock pll\n", clk_hw_get_name(&pll->common.hw)); + + return regmap_set_bits(pll->common.regmap, + pll->syscon_offset + pll->pll.enable_offset, + BIT(pll->pll.enable_bit)); + } + + return regmap_clear_bits(pll->common.regmap, + pll->syscon_offset + pll->pll.enable_offset, + BIT(pll->pll.enable_bit)); +} + +static int sg2044_pll_update_vcosel(struct sg2044_pll *pll, u64 rate) +{ + unsigned int sel; + + if (rate < U64_C(2400000000)) + sel = PLL_VCOSEL_1G6; + else + sel = PLL_VCOSEL_2G4; + + return regmap_write_bits(pll->common.regmap, + pll->syscon_offset + pll->pll.ctrl_offset, + PLL_VCOSEL_MASK, + FIELD_PREP(PLL_VCOSEL_MASK, sel)); +} + +static int sg2044_pll_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct sg2044_pll *pll = hw_to_sg2044_pll(hw); + unsigned int value; + u64 vco; + int ret; + + ret = sg2044_compute_pll_setting(pll->pll.limits, rate, + parent_rate, &value); + if (ret < 0) + return ret; + + vco = sg2044_pll_calc_vco_rate(parent_rate, + FIELD_GET(PLL_REFDIV_MASK, value), + FIELD_GET(PLL_FBDIV_MASK, value)); + + value |= PLL_CALIBRATE_EN; + value |= PLL_CALIBRATE_DEFAULT; + value |= PLL_UPDATE_EN; + + guard(spinlock_irqsave)(pll->common.lock); + + ret = sg2044_pll_enable(pll, false); + if (ret) + return ret; + + sg2044_pll_update_vcosel(pll, vco); + + regmap_write_bits(pll->common.regmap, + pll->syscon_offset + pll->pll.ctrl_offset + + PLL_HIGH_CTRL_OFFSET, + PLL_HIGH_CTRL_MASK, value); + + sg2044_pll_enable(pll, true); + + return ret; +} + +static const struct clk_ops sg2044_pll_ops = { + .recalc_rate = sg2044_pll_recalc_rate, + .determine_rate = sg2044_pll_determine_rate, + .set_rate = sg2044_pll_set_rate, +}; + +static const struct clk_ops sg2044_pll_ro_ops = { + .recalc_rate = sg2044_pll_recalc_rate, +}; + +#define SG2044_CLK_COMMON_PDATA(_id, _name, _parents, _op, _flags) \ + { \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \ + _op, (_flags)), \ + .id = (_id), \ + } + +#define DEFINE_SG2044_PLL(_id, _name, _parent, _flags, \ + _ctrl_offset, \ + _status_offset, _status_lock_bit, \ + _status_updating_bit, \ + _enable_offset, _enable_bit, \ + _limits) \ + struct sg2044_pll _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &sg2044_pll_ops, \ + (_flags)), \ + .pll = { \ + .ctrl_offset = (_ctrl_offset), \ + .status_offset = (_status_offset), \ + .enable_offset = (_enable_offset), \ + .status_lock_bit = (_status_lock_bit), \ + .status_updating_bit = (_status_updating_bit), \ + .enable_bit = (_enable_bit), \ + .limits = (_limits), \ + }, \ + } + +#define DEFINE_SG2044_PLL_RO(_id, _name, _parent, _flags, \ + _ctrl_offset, \ + _status_offset, _status_lock_bit, \ + _status_updating_bit, \ + _enable_offset, _enable_bit, \ + _limits) \ + struct sg2044_pll _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &sg2044_pll_ro_ops, \ + (_flags)), \ + .pll = { \ + .ctrl_offset = (_ctrl_offset), \ + .status_offset = (_status_offset), \ + .enable_offset = (_enable_offset), \ + .status_lock_bit = (_status_lock_bit), \ + .status_updating_bit = (_status_updating_bit), \ + .enable_bit = (_enable_bit), \ + .limits = (_limits), \ + }, \ + } + +static const struct clk_parent_data osc_parents[] = { + { .index = 0 }, +}; + +static const struct sg2044_pll_limit pll_limits[] = { + [PLL_LIMIT_FOUTVCO] = { + .min = U64_C(1600000000), + .max = U64_C(3200000000), + }, + [PLL_LIMIT_FOUT] = { + .min = U64_C(25000), + .max = U64_C(3200000000), + }, + [PLL_LIMIT_REFDIV] = { + .min = U64_C(1), + .max = U64_C(63), + }, + [PLL_LIMIT_FBDIV] = { + .min = U64_C(8), + .max = U64_C(1066), + }, + [PLL_LIMIT_POSTDIV1] = { + .min = U64_C(0), + .max = U64_C(7), + }, + [PLL_LIMIT_POSTDIV2] = { + .min = U64_C(0), + .max = U64_C(7), + }, +}; + +static DEFINE_SG2044_PLL_RO(CLK_FPLL0, clk_fpll0, osc_parents, CLK_IS_CRITICAL, + 0x58, 0x00, 22, 6, + 0x04, 6, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_FPLL1, clk_fpll1, osc_parents, CLK_IS_CRITICAL, + 0x60, 0x00, 23, 7, + 0x04, 7, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_FPLL2, clk_fpll2, osc_parents, CLK_IS_CRITICAL, + 0x20, 0x08, 16, 0, + 0x0c, 0, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL0, clk_dpll0, osc_parents, CLK_IS_CRITICAL, + 0x68, 0x00, 24, 8, + 0x04, 8, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL1, clk_dpll1, osc_parents, CLK_IS_CRITICAL, + 0x70, 0x00, 25, 9, + 0x04, 9, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL2, clk_dpll2, osc_parents, CLK_IS_CRITICAL, + 0x78, 0x00, 26, 10, + 0x04, 10, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL3, clk_dpll3, osc_parents, CLK_IS_CRITICAL, + 0x80, 0x00, 27, 11, + 0x04, 11, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL4, clk_dpll4, osc_parents, CLK_IS_CRITICAL, + 0x88, 0x00, 28, 12, + 0x04, 12, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL5, clk_dpll5, osc_parents, CLK_IS_CRITICAL, + 0x90, 0x00, 29, 13, + 0x04, 13, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL6, clk_dpll6, osc_parents, CLK_IS_CRITICAL, + 0x98, 0x00, 30, 14, + 0x04, 14, pll_limits); + +static DEFINE_SG2044_PLL_RO(CLK_DPLL7, clk_dpll7, osc_parents, CLK_IS_CRITICAL, + 0xa0, 0x00, 31, 15, + 0x04, 15, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL0, clk_mpll0, osc_parents, CLK_IS_CRITICAL, + 0x28, 0x00, 16, 0, + 0x04, 0, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL1, clk_mpll1, osc_parents, CLK_IS_CRITICAL, + 0x30, 0x00, 17, 1, + 0x04, 1, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL2, clk_mpll2, osc_parents, CLK_IS_CRITICAL, + 0x38, 0x00, 18, 2, + 0x04, 2, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL3, clk_mpll3, osc_parents, CLK_IS_CRITICAL, + 0x40, 0x00, 19, 3, + 0x04, 3, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL4, clk_mpll4, osc_parents, CLK_IS_CRITICAL, + 0x48, 0x00, 20, 4, + 0x04, 4, pll_limits); + +static DEFINE_SG2044_PLL(CLK_MPLL5, clk_mpll5, osc_parents, CLK_IS_CRITICAL, + 0x50, 0x00, 21, 5, + 0x04, 5, pll_limits); + +static struct sg2044_clk_common * const sg2044_pll_commons[] = { + &clk_fpll0.common, + &clk_fpll1.common, + &clk_fpll2.common, + &clk_dpll0.common, + &clk_dpll1.common, + &clk_dpll2.common, + &clk_dpll3.common, + &clk_dpll4.common, + &clk_dpll5.common, + &clk_dpll6.common, + &clk_dpll7.common, + &clk_mpll0.common, + &clk_mpll1.common, + &clk_mpll2.common, + &clk_mpll3.common, + &clk_mpll4.common, + &clk_mpll5.common, +}; + +static int sg2044_pll_init_ctrl(struct device *dev, struct regmap *regmap, + struct sg2044_pll_ctrl *ctrl, + const struct sg2044_pll_desc_data *desc) +{ + int ret, i; + + spin_lock_init(&ctrl->lock); + + for (i = 0; i < desc->num_pll; i++) { + struct sg2044_clk_common *common = desc->pll[i]; + struct sg2044_pll *pll = hw_to_sg2044_pll(&common->hw); + + common->lock = &ctrl->lock; + common->regmap = regmap; + pll->syscon_offset = SG2044_SYSCON_PLL_OFFSET; + + ret = devm_clk_hw_register(dev, &common->hw); + if (ret) + return ret; + + ctrl->data.hws[common->id] = &common->hw; + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &ctrl->data); +} + +static int sg2044_pll_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sg2044_pll_ctrl *ctrl; + const struct sg2044_pll_desc_data *desc; + struct regmap *regmap; + + regmap = device_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "fail to get the regmap for PLL\n"); + + desc = (const struct sg2044_pll_desc_data *)platform_get_device_id(pdev)->driver_data; + if (!desc) + return dev_err_probe(dev, -EINVAL, "no match data for platform\n"); + + ctrl = devm_kzalloc(dev, struct_size(ctrl, data.hws, desc->num_pll), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->data.num = desc->num_pll; + + return sg2044_pll_init_ctrl(dev, regmap, ctrl, desc); +} + +static const struct sg2044_pll_desc_data sg2044_pll_desc_data = { + .pll = sg2044_pll_commons, + .num_pll = ARRAY_SIZE(sg2044_pll_commons), +}; + +static const struct platform_device_id sg2044_pll_match[] = { + { .name = "sg2044-pll", + .driver_data = (unsigned long)&sg2044_pll_desc_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, sg2044_pll_match); + +static struct platform_driver sg2044_clk_driver = { + .probe = sg2044_pll_probe, + .driver = { + .name = "sg2044-pll", + }, + .id_table = sg2044_pll_match, +}; +module_platform_driver(sg2044_clk_driver); + +MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>"); +MODULE_DESCRIPTION("Sophgo SG2044 pll clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sophgo/clk-sg2044.c b/drivers/clk/sophgo/clk-sg2044.c new file mode 100644 index 000000000000..f67f99c926b6 --- /dev/null +++ b/drivers/clk/sophgo/clk-sg2044.c @@ -0,0 +1,1812 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sophgo SG2044 clock controller driver + * + * Copyright (C) 2025 Inochi Amaoto <inochiama@gmail.com> + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/math64.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/spinlock.h> + +#include <dt-bindings/clock/sophgo,sg2044-clk.h> + +#define DIV_ASSERT BIT(0) +#define DIV_FACTOR_REG_SOURCE BIT(3) +#define DIV_BRANCH_EN BIT(4) + +#define DIV_ASSERT_TIME 2 + +struct sg2044_div_internal { + u32 offset; + u32 initval; + u8 shift; + u8 width; + u16 flags; +}; + +struct sg2044_mux_internal { + const u32 *table; + u32 offset; + u16 shift; + u16 flags; +}; + +struct sg2044_gate_internal { + u32 offset; + u16 shift; + u16 flags; +}; + +struct sg2044_clk_common { + struct clk_hw hw; + void __iomem *base; + spinlock_t *lock; + unsigned int id; +}; + +struct sg2044_div { + struct sg2044_clk_common common; + struct sg2044_div_internal div; +}; + +struct sg2044_mux { + struct sg2044_clk_common common; + struct sg2044_mux_internal mux; + struct notifier_block nb; + u8 saved_parent; +}; + +struct sg2044_gate { + struct sg2044_clk_common common; + struct sg2044_gate_internal gate; +}; + +struct sg2044_clk_ctrl { + spinlock_t lock; + struct clk_hw_onecell_data data; +}; + +struct sg2044_clk_desc_data { + struct sg2044_clk_common * const *pll; + struct sg2044_clk_common * const *div; + struct sg2044_clk_common * const *mux; + struct sg2044_clk_common * const *gate; + u16 num_pll; + u16 num_div; + u16 num_mux; + u16 num_gate; +}; + +#define hw_to_sg2044_clk_common(_hw) \ + container_of((_hw), struct sg2044_clk_common, hw) + +static inline struct sg2044_div *hw_to_sg2044_div(struct clk_hw *hw) +{ + return container_of(hw_to_sg2044_clk_common(hw), + struct sg2044_div, common); +} + +static u32 sg2044_div_get_reg_div(u32 reg, struct sg2044_div_internal *div) +{ + if ((reg & DIV_FACTOR_REG_SOURCE)) + return (reg >> div->shift) & clk_div_mask(div->width); + + return div->initval == 0 ? 1 : div->initval; +} + +static unsigned long _sg2044_div_recalc_rate(struct sg2044_clk_common *common, + struct sg2044_div_internal *div, + unsigned long parent_rate) +{ + u32 reg = readl(common->base + div->offset); + u32 val = sg2044_div_get_reg_div(reg, div); + + return divider_recalc_rate(&common->hw, parent_rate, val, NULL, + div->flags, div->width); +} + +static unsigned long sg2044_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + + return _sg2044_div_recalc_rate(&div->common, &div->div, + parent_rate); +} + +static int _sg2044_div_determine_rate(struct sg2044_clk_common *common, + struct sg2044_div_internal *div, + struct clk_rate_request *req) +{ + if (div->flags & CLK_DIVIDER_READ_ONLY) { + u32 reg = readl(common->base + div->offset); + u32 val = sg2044_div_get_reg_div(reg, div); + + return divider_ro_determine_rate(&common->hw, req, NULL, + div->width, div->flags, + val); + } + + return divider_determine_rate(&common->hw, req, NULL, + div->width, div->flags); +} + +static int sg2044_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + + return _sg2044_div_determine_rate(&div->common, &div->div, req); +} + +static void sg2044_div_set_reg_div(struct sg2044_clk_common *common, + struct sg2044_div_internal *div, + u32 value) +{ + void __iomem *addr = common->base + div->offset; + u32 reg; + + reg = readl(addr); + + /* assert */ + reg &= ~DIV_ASSERT; + writel(reg, addr); + + /* set value */ + reg = readl(addr); + reg &= ~(clk_div_mask(div->width) << div->shift); + reg |= (value << div->shift) | DIV_FACTOR_REG_SOURCE; + writel(reg, addr); + + /* de-assert */ + reg |= DIV_ASSERT; + writel(reg, addr); +} + +static int sg2044_div_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + u32 value; + + value = divider_get_val(rate, parent_rate, NULL, + div->div.width, div->div.flags); + + guard(spinlock_irqsave)(div->common.lock); + + sg2044_div_set_reg_div(&div->common, &div->div, value); + + return 0; +} + +static int sg2044_div_enable(struct clk_hw *hw) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + void __iomem *addr = div->common.base + div->div.offset; + u32 value; + + guard(spinlock_irqsave)(div->common.lock); + + value = readl(addr); + value |= DIV_BRANCH_EN; + writel(value, addr); + + return 0; +} + +static void sg2044_div_disable(struct clk_hw *hw) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + void __iomem *addr = div->common.base + div->div.offset; + u32 value; + + guard(spinlock_irqsave)(div->common.lock); + + value = readl(addr); + value &= ~DIV_BRANCH_EN; + writel(value, addr); +} + +static int sg2044_div_is_enabled(struct clk_hw *hw) +{ + struct sg2044_div *div = hw_to_sg2044_div(hw); + + return readl(div->common.base + div->div.offset) & DIV_BRANCH_EN; +} + +static const struct clk_ops sg2044_gateable_div_ops = { + .enable = sg2044_div_enable, + .disable = sg2044_div_disable, + .is_enabled = sg2044_div_is_enabled, + .recalc_rate = sg2044_div_recalc_rate, + .determine_rate = sg2044_div_determine_rate, + .set_rate = sg2044_div_set_rate, +}; + +static const struct clk_ops sg2044_div_ops = { + .recalc_rate = sg2044_div_recalc_rate, + .determine_rate = sg2044_div_determine_rate, + .set_rate = sg2044_div_set_rate, +}; + +static const struct clk_ops sg2044_div_ro_ops = { + .recalc_rate = sg2044_div_recalc_rate, + .determine_rate = sg2044_div_determine_rate, +}; + +static inline struct sg2044_mux *hw_to_sg2044_mux(struct clk_hw *hw) +{ + return container_of(hw_to_sg2044_clk_common(hw), + struct sg2044_mux, common); +} + +static inline struct sg2044_mux *nb_to_sg2044_mux(struct notifier_block *nb) +{ + return container_of(nb, struct sg2044_mux, nb); +} + +static const u32 sg2044_mux_table[] = {0, 1}; + +static int sg2044_mux_notifier_cb(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct sg2044_mux *mux = nb_to_sg2044_mux(nb); + const struct clk_ops *ops = &clk_mux_ops; + struct clk_notifier_data *ndata = data; + struct clk_hw *hw = __clk_get_hw(ndata->clk); + int ret = 0; + + if (event == PRE_RATE_CHANGE) { + mux->saved_parent = ops->get_parent(hw); + if (mux->saved_parent) + ret = ops->set_parent(hw, 0); + } else if (event == POST_RATE_CHANGE) { + ret = ops->set_parent(hw, mux->saved_parent); + } + + return notifier_from_errno(ret); +} + +static inline struct sg2044_gate *hw_to_sg2044_gate(struct clk_hw *hw) +{ + return container_of(hw_to_sg2044_clk_common(hw), + struct sg2044_gate, common); +} + +#define SG2044_CLK_COMMON_PDATA(_id, _name, _parents, _op, _flags) \ + { \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \ + _op, (_flags)), \ + .id = (_id), \ + } + +#define SG2044_CLK_COMMON_PHWS(_id, _name, _parents, _op, _flags) \ + { \ + .hw.init = CLK_HW_INIT_PARENTS_HW(_name, _parents, \ + _op, (_flags)), \ + .id = (_id), \ + } + +#define DEFINE_SG2044_GATEABLE_DIV(_id, _name, _parent, _flags, \ + _div_offset, _div_shift, _div_width, \ + _div_flags, _div_initval) \ + struct sg2044_div _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &sg2044_gateable_div_ops,\ + (_flags)), \ + .div = { \ + .offset = (_div_offset), \ + .initval = (_div_initval), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + .flags = (_div_flags), \ + }, \ + } + +#define DEFINE_SG2044_DIV(_id, _name, _parent, _flags, \ + _div_offset, _div_shift, _div_width, \ + _div_flags, _div_initval) \ + struct sg2044_div _name = { \ + .common = SG2044_CLK_COMMON_PHWS(_id, #_name, _parent, \ + &sg2044_div_ops, \ + (_flags)), \ + .div = { \ + .offset = (_div_offset), \ + .initval = (_div_initval), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + .flags = (_div_flags), \ + }, \ + } + +#define DEFINE_SG2044_DIV_PDATA(_id, _name, _parent, _flags, \ + _div_offset, _div_shift, _div_width, \ + _div_flags, _div_initval) \ + struct sg2044_div _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &sg2044_div_ops, \ + (_flags)), \ + .div = { \ + .offset = (_div_offset), \ + .initval = (_div_initval), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + .flags = (_div_flags), \ + }, \ + } + +#define DEFINE_SG2044_DIV_RO(_id, _name, _parent, _flags, \ + _div_offset, _div_shift, _div_width, \ + _div_flags, _div_initval) \ + struct sg2044_div _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &sg2044_div_ro_ops, \ + (_flags)), \ + .div = { \ + .offset = (_div_offset), \ + .initval = (_div_initval), \ + .shift = (_div_shift), \ + .width = (_div_width), \ + .flags = (_div_flags) | CLK_DIVIDER_READ_ONLY,\ + }, \ + } + +#define DEFINE_SG2044_MUX(_id, _name, _parent, _flags, \ + _mux_offset, _mux_shift, \ + _mux_table, _mux_flags) \ + struct sg2044_mux _name = { \ + .common = SG2044_CLK_COMMON_PDATA(_id, #_name, _parent, \ + &clk_mux_ops, (_flags)),\ + .mux = { \ + .table = (_mux_table), \ + .offset = (_mux_offset), \ + .shift = (_mux_shift), \ + .flags = (_mux_flags), \ + }, \ + } + +#define DEFINE_SG2044_GATE(_id, _name, _parent, _flags, \ + _gate_offset, _gate_shift, _gate_flags) \ + struct sg2044_gate _name = { \ + .common = SG2044_CLK_COMMON_PHWS(_id, #_name, _parent, \ + &clk_gate_ops, (_flags)),\ + .gate = { \ + .offset = (_gate_offset), \ + .shift = (_gate_shift), \ + .flags = (_gate_flags), \ + }, \ + } + +static const struct clk_parent_data clk_fpll0_parent[] = { + { .fw_name = "fpll0" }, +}; + +static const struct clk_parent_data clk_fpll1_parent[] = { + { .fw_name = "fpll1" }, +}; + +static const struct clk_parent_data clk_fpll2_parent[] = { + { .fw_name = "fpll2" }, +}; + +static const struct clk_parent_data clk_dpll0_parent[] = { + { .fw_name = "dpll0" }, +}; + +static const struct clk_parent_data clk_dpll1_parent[] = { + { .fw_name = "dpll1" }, +}; + +static const struct clk_parent_data clk_dpll2_parent[] = { + { .fw_name = "dpll2" }, +}; + +static const struct clk_parent_data clk_dpll3_parent[] = { + { .fw_name = "dpll3" }, +}; + +static const struct clk_parent_data clk_dpll4_parent[] = { + { .fw_name = "dpll4" }, +}; + +static const struct clk_parent_data clk_dpll5_parent[] = { + { .fw_name = "dpll5" }, +}; + +static const struct clk_parent_data clk_dpll6_parent[] = { + { .fw_name = "dpll6" }, +}; + +static const struct clk_parent_data clk_dpll7_parent[] = { + { .fw_name = "dpll7" }, +}; + +static const struct clk_parent_data clk_mpll0_parent[] = { + { .fw_name = "mpll0" }, +}; + +static const struct clk_parent_data clk_mpll1_parent[] = { + { .fw_name = "mpll1" }, +}; + +static const struct clk_parent_data clk_mpll2_parent[] = { + { .fw_name = "mpll2" }, +}; + +static const struct clk_parent_data clk_mpll3_parent[] = { + { .fw_name = "mpll3" }, +}; + +static const struct clk_parent_data clk_mpll4_parent[] = { + { .fw_name = "mpll4" }, +}; + +static const struct clk_parent_data clk_mpll5_parent[] = { + { .fw_name = "mpll5" }, +}; + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_AP_SYS_FIXED, clk_div_ap_sys_fixed, + clk_fpll0_parent, 0, + 0x044, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_AP_SYS_MAIN, clk_div_ap_sys_main, + clk_mpll0_parent, 0, + 0x040, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_RP_SYS_FIXED, clk_div_rp_sys_fixed, + clk_fpll0_parent, 0, + 0x050, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_RP_SYS_MAIN, clk_div_rp_sys_main, + clk_mpll1_parent, 0, + 0x04c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_TPU_SYS_FIXED, clk_div_tpu_sys_fixed, + clk_fpll0_parent, 0, + 0x058, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 2); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_TPU_SYS_MAIN, clk_div_tpu_sys_main, + clk_mpll2_parent, 0, + 0x054, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_NOC_SYS_FIXED, clk_div_noc_sys_fixed, + clk_fpll0_parent, 0, + 0x070, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_NOC_SYS_MAIN, clk_div_noc_sys_main, + clk_mpll3_parent, 0, + 0x06c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_VC_SRC0_FIXED, clk_div_vc_src0_fixed, + clk_fpll0_parent, 0, + 0x078, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 2); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_VC_SRC0_MAIN, clk_div_vc_src0_main, + clk_mpll4_parent, 0, + 0x074, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_VC_SRC1_FIXED, clk_div_vc_src1_fixed, + clk_fpll0_parent, 0, + 0x080, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 3); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_VC_SRC1_MAIN, clk_div_vc_src1_main, + clk_mpll5_parent, 0, + 0x07c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_CXP_MAC_FIXED, clk_div_cxp_mac_fixed, + clk_fpll0_parent, 0, + 0x088, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 2); + +static DEFINE_SG2044_GATEABLE_DIV(CLK_DIV_CXP_MAC_MAIN, clk_div_cxp_mac_main, + clk_fpll1_parent, 0, + 0x084, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO | + CLK_IS_CRITICAL, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR0_FIXED, clk_div_ddr0_fixed, + clk_fpll0_parent, 0, + 0x124, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR0_MAIN, clk_div_ddr0_main, + clk_dpll0_parent, 0, + 0x120, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR1_FIXED, clk_div_ddr1_fixed, + clk_fpll0_parent, 0, + 0x12c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR1_MAIN, clk_div_ddr1_main, + clk_dpll1_parent, 0, + 0x128, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR2_FIXED, clk_div_ddr2_fixed, + clk_fpll0_parent, 0, + 0x134, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR2_MAIN, clk_div_ddr2_main, + clk_dpll2_parent, 0, + 0x130, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR3_FIXED, clk_div_ddr3_fixed, + clk_fpll0_parent, 0, + 0x13c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR3_MAIN, clk_div_ddr3_main, + clk_dpll3_parent, 0, + 0x138, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR4_FIXED, clk_div_ddr4_fixed, + clk_fpll0_parent, 0, + 0x144, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR4_MAIN, clk_div_ddr4_main, + clk_dpll4_parent, 0, + 0x140, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR5_FIXED, clk_div_ddr5_fixed, + clk_fpll0_parent, 0, + 0x14c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR5_MAIN, clk_div_ddr5_main, + clk_dpll5_parent, 0, + 0x148, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR6_FIXED, clk_div_ddr6_fixed, + clk_fpll0_parent, 0, + 0x154, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR6_MAIN, clk_div_ddr6_main, + clk_dpll6_parent, 0, + 0x150, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR7_FIXED, clk_div_ddr7_fixed, + clk_fpll0_parent, 0, + 0x15c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static DEFINE_SG2044_DIV_RO(CLK_DIV_DDR7_MAIN, clk_div_ddr7_main, + clk_dpll7_parent, 0, + 0x158, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_TOP_50M, clk_div_top_50m, + clk_fpll0_parent, 0, + 0x048, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 40); + +static const struct clk_hw *clk_div_top_50m_parent[] = { + &clk_div_top_50m.common.hw, +}; + +static DEFINE_SG2044_DIV_RO(CLK_DIV_TOP_AXI0, clk_div_top_axi0, + clk_fpll0_parent, 0, + 0x118, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 20); + +static const struct clk_hw *clk_div_top_axi0_parent[] = { + &clk_div_top_axi0.common.hw, +}; + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_TOP_AXI_HSPERI, clk_div_top_axi_hsperi, + clk_fpll0_parent, 0, + 0x11c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 8); + +static const struct clk_hw *clk_div_top_axi_hsperi_parent[] = { + &clk_div_top_axi_hsperi.common.hw, +}; + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER0, clk_div_timer0, + clk_div_top_50m_parent, 0, + 0x0d0, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER1, clk_div_timer1, + clk_div_top_50m_parent, 0, + 0x0d4, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER2, clk_div_timer2, + clk_div_top_50m_parent, 0, + 0x0d8, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER3, clk_div_timer3, + clk_div_top_50m_parent, 0, + 0x0dc, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER4, clk_div_timer4, + clk_div_top_50m_parent, 0, + 0x0e0, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER5, clk_div_timer5, + clk_div_top_50m_parent, 0, + 0x0e4, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER6, clk_div_timer6, + clk_div_top_50m_parent, 0, + 0x0e8, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV(CLK_DIV_TIMER7, clk_div_timer7, + clk_div_top_50m_parent, 0, + 0x0ec, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_CXP_TEST_PHY, clk_div_cxp_test_phy, + clk_fpll0_parent, 0, + 0x064, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_CXP_TEST_ETH_PHY, clk_div_cxp_test_eth_phy, + clk_fpll2_parent, 0, + 0x068, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_C2C0_TEST_PHY, clk_div_c2c0_test_phy, + clk_fpll0_parent, 0, + 0x05c, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_C2C1_TEST_PHY, clk_div_c2c1_test_phy, + clk_fpll0_parent, 0, + 0x060, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_PCIE_1G, clk_div_pcie_1g, + clk_fpll1_parent, 0, + 0x160, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_UART_500M, clk_div_uart_500m, + clk_fpll0_parent, 0, + 0x0cc, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 4); + +static DEFINE_SG2044_DIV(CLK_DIV_GPIO_DB, clk_div_gpio_db, + clk_div_top_axi0_parent, 0, + 0x0f8, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1000); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_SD, clk_div_sd, + clk_fpll0_parent, 0, + 0x110, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 5); + +static DEFINE_SG2044_DIV(CLK_DIV_SD_100K, clk_div_sd_100k, + clk_div_top_axi0_parent, 0, + 0x114, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1000); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_EMMC, clk_div_emmc, + clk_fpll0_parent, 0, + 0x108, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 5); + +static DEFINE_SG2044_DIV(CLK_DIV_EMMC_100K, clk_div_emmc_100k, + clk_div_top_axi0_parent, 0, + 0x10c, 16, 16, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 1000); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_EFUSE, clk_div_efuse, + clk_fpll0_parent, 0, + 0x0f4, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 80); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_TX_ETH0, clk_div_tx_eth0, + clk_fpll0_parent, 0, + 0x0fc, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 16); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_PTP_REF_I_ETH0, clk_div_ptp_ref_i_eth0, + clk_fpll0_parent, 0, + 0x100, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 40); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_REF_ETH0, clk_div_ref_eth0, + clk_fpll0_parent, 0, + 0x104, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 80); + +static DEFINE_SG2044_DIV_PDATA(CLK_DIV_PKA, clk_div_pka, + clk_fpll0_parent, 0, + 0x0f0, 16, 8, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + 2); + +static const struct clk_parent_data clk_mux_ddr0_parents[] = { + { .hw = &clk_div_ddr0_fixed.common.hw }, + { .hw = &clk_div_ddr0_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR0, clk_mux_ddr0, + clk_mux_ddr0_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 7, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr1_parents[] = { + { .hw = &clk_div_ddr1_fixed.common.hw }, + { .hw = &clk_div_ddr1_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR1, clk_mux_ddr1, + clk_mux_ddr1_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 8, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr2_parents[] = { + { .hw = &clk_div_ddr2_fixed.common.hw }, + { .hw = &clk_div_ddr2_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR2, clk_mux_ddr2, + clk_mux_ddr2_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 9, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr3_parents[] = { + { .hw = &clk_div_ddr3_fixed.common.hw }, + { .hw = &clk_div_ddr3_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR3, clk_mux_ddr3, + clk_mux_ddr3_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 10, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr4_parents[] = { + { .hw = &clk_div_ddr4_fixed.common.hw }, + { .hw = &clk_div_ddr4_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR4, clk_mux_ddr4, + clk_mux_ddr4_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 11, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr5_parents[] = { + { .hw = &clk_div_ddr5_fixed.common.hw }, + { .hw = &clk_div_ddr5_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR5, clk_mux_ddr5, + clk_mux_ddr5_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 12, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr6_parents[] = { + { .hw = &clk_div_ddr6_fixed.common.hw }, + { .hw = &clk_div_ddr6_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR6, clk_mux_ddr6, + clk_mux_ddr6_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 13, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_ddr7_parents[] = { + { .hw = &clk_div_ddr7_fixed.common.hw }, + { .hw = &clk_div_ddr7_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_DDR7, clk_mux_ddr7, + clk_mux_ddr7_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 14, sg2044_mux_table, CLK_MUX_READ_ONLY); + +static const struct clk_parent_data clk_mux_noc_sys_parents[] = { + { .hw = &clk_div_noc_sys_fixed.common.hw }, + { .hw = &clk_div_noc_sys_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_NOC_SYS, clk_mux_noc_sys, + clk_mux_noc_sys_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 3, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_tpu_sys_parents[] = { + { .hw = &clk_div_tpu_sys_fixed.common.hw }, + { .hw = &clk_div_tpu_sys_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_TPU_SYS, clk_mux_tpu_sys, + clk_mux_tpu_sys_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 2, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_rp_sys_parents[] = { + { .hw = &clk_div_rp_sys_fixed.common.hw }, + { .hw = &clk_div_rp_sys_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_RP_SYS, clk_mux_rp_sys, + clk_mux_rp_sys_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 1, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_ap_sys_parents[] = { + { .hw = &clk_div_ap_sys_fixed.common.hw }, + { .hw = &clk_div_ap_sys_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_AP_SYS, clk_mux_ap_sys, + clk_mux_ap_sys_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 0, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_vc_src0_parents[] = { + { .hw = &clk_div_vc_src0_fixed.common.hw }, + { .hw = &clk_div_vc_src0_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_VC_SRC0, clk_mux_vc_src0, + clk_mux_vc_src0_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 4, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_vc_src1_parents[] = { + { .hw = &clk_div_vc_src1_fixed.common.hw }, + { .hw = &clk_div_vc_src1_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_VC_SRC1, clk_mux_vc_src1, + clk_mux_vc_src1_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 5, sg2044_mux_table, 0); + +static const struct clk_parent_data clk_mux_cxp_mac_parents[] = { + { .hw = &clk_div_cxp_mac_fixed.common.hw }, + { .hw = &clk_div_cxp_mac_main.common.hw }, +}; + +static DEFINE_SG2044_MUX(CLK_MUX_CXP_MAC, clk_mux_cxp_mac, + clk_mux_cxp_mac_parents, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + 0x020, 6, sg2044_mux_table, 0); + +static const struct clk_hw *clk_gate_ap_sys_parent[] = { + &clk_mux_ap_sys.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_AP_SYS, clk_gate_ap_sys, + clk_gate_ap_sys_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 0, 0); + +static const struct clk_hw *clk_gate_rp_sys_parent[] = { + &clk_mux_rp_sys.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_RP_SYS, clk_gate_rp_sys, + clk_gate_rp_sys_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 2, 0); + +static const struct clk_hw *clk_gate_tpu_sys_parent[] = { + &clk_mux_tpu_sys.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TPU_SYS, clk_gate_tpu_sys, + clk_gate_tpu_sys_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 3, 0); + +static const struct clk_hw *clk_gate_noc_sys_parent[] = { + &clk_mux_noc_sys.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_NOC_SYS, clk_gate_noc_sys, + clk_gate_noc_sys_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 8, 0); + +static const struct clk_hw *clk_gate_vc_src0_parent[] = { + &clk_mux_vc_src0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_VC_SRC0, clk_gate_vc_src0, + clk_gate_vc_src0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 9, 0); + +static const struct clk_hw *clk_gate_vc_src1_parent[] = { + &clk_mux_vc_src1.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_VC_SRC1, clk_gate_vc_src1, + clk_gate_vc_src1_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 10, 0); + +static const struct clk_hw *clk_gate_ddr0_parent[] = { + &clk_mux_ddr0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR0, clk_gate_ddr0, + clk_gate_ddr0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 7, 0); + +static const struct clk_hw *clk_gate_ddr1_parent[] = { + &clk_mux_ddr1.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR1, clk_gate_ddr1, + clk_gate_ddr1_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 8, 0); + +static const struct clk_hw *clk_gate_ddr2_parent[] = { + &clk_mux_ddr2.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR2, clk_gate_ddr2, + clk_gate_ddr2_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 9, 0); + +static const struct clk_hw *clk_gate_ddr3_parent[] = { + &clk_mux_ddr3.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR3, clk_gate_ddr3, + clk_gate_ddr3_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 10, 0); + +static const struct clk_hw *clk_gate_ddr4_parent[] = { + &clk_mux_ddr4.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR4, clk_gate_ddr4, + clk_gate_ddr4_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 11, 0); + +static const struct clk_hw *clk_gate_ddr5_parent[] = { + &clk_mux_ddr5.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR5, clk_gate_ddr5, + clk_gate_ddr5_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 12, 0); + +static const struct clk_hw *clk_gate_ddr6_parent[] = { + &clk_mux_ddr6.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR6, clk_gate_ddr6, + clk_gate_ddr6_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 13, 0); + +static const struct clk_hw *clk_gate_ddr7_parent[] = { + &clk_mux_ddr7.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_DDR7, clk_gate_ddr7, + clk_gate_ddr7_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 14, 0); + +static const struct clk_hw *clk_gate_top_50m_parent[] = { + &clk_div_top_50m.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TOP_50M, clk_gate_top_50m, + clk_gate_top_50m_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 1, 0); + +static const struct clk_hw *clk_gate_sc_rx_parent[] = { + &clk_div_top_50m.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_SC_RX, clk_gate_sc_rx, + clk_gate_sc_rx_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 12, 0); + +static const struct clk_hw *clk_gate_sc_rx_x0y1_parent[] = { + &clk_div_top_50m.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_SC_RX_X0Y1, clk_gate_sc_rx_x0y1, + clk_gate_sc_rx_x0y1_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 13, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_TOP_AXI0, clk_gate_top_axi0, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 5, 0); + +static const struct clk_hw *clk_gate_mailbox_intc_parent[] = { + &clk_gate_top_axi0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_INTC0, clk_gate_intc0, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 20, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_INTC1, clk_gate_intc1, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 21, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_INTC2, clk_gate_intc2, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 22, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_INTC3, clk_gate_intc3, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 23, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_MAILBOX0, clk_gate_mailbox0, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 16, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_MAILBOX1, clk_gate_mailbox1, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 17, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_MAILBOX2, clk_gate_mailbox2, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 18, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_MAILBOX3, clk_gate_mailbox3, + clk_gate_mailbox_intc_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x020, 19, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_TOP_AXI_HSPERI, clk_gate_top_axi_hsperi, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x008, 6, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_TIMER, clk_gate_apb_timer, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT, + 0x004, 7, 0); + +static const struct clk_hw *clk_gate_timer0_parent[] = { + &clk_div_timer0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER0, clk_gate_timer0, + clk_gate_timer0_parent, + CLK_SET_RATE_PARENT, + 0x004, 8, 0); + +static const struct clk_hw *clk_gate_timer1_parent[] = { + &clk_div_timer1.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER1, clk_gate_timer1, + clk_gate_timer1_parent, + CLK_SET_RATE_PARENT, + 0x004, 9, 0); + +static const struct clk_hw *clk_gate_timer2_parent[] = { + &clk_div_timer2.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER2, clk_gate_timer2, + clk_gate_timer2_parent, + CLK_SET_RATE_PARENT, + 0x004, 10, 0); + +static const struct clk_hw *clk_gate_timer3_parent[] = { + &clk_div_timer3.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER3, clk_gate_timer3, + clk_gate_timer3_parent, + CLK_SET_RATE_PARENT, + 0x004, 11, 0); + +static const struct clk_hw *clk_gate_timer4_parent[] = { + &clk_div_timer4.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER4, clk_gate_timer4, + clk_gate_timer4_parent, + CLK_SET_RATE_PARENT, + 0x004, 12, 0); + +static const struct clk_hw *clk_gate_timer5_parent[] = { + &clk_div_timer5.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER5, clk_gate_timer5, + clk_gate_timer5_parent, + CLK_SET_RATE_PARENT, + 0x004, 13, 0); + +static const struct clk_hw *clk_gate_timer6_parent[] = { + &clk_div_timer6.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER6, clk_gate_timer6, + clk_gate_timer6_parent, + CLK_SET_RATE_PARENT, + 0x004, 14, 0); + +static const struct clk_hw *clk_gate_timer7_parent[] = { + &clk_div_timer7.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TIMER7, clk_gate_timer7, + clk_gate_timer7_parent, + CLK_SET_RATE_PARENT, + 0x004, 15, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_CXP_CFG, clk_gate_cxp_cfg, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 15, 0); + +static const struct clk_hw *clk_gate_cxp_mac_parent[] = { + &clk_mux_cxp_mac.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_CXP_MAC, clk_gate_cxp_mac, + clk_gate_cxp_mac_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x000, 14, 0); + +static const struct clk_hw *clk_gate_cxp_test_phy_parent[] = { + &clk_div_cxp_test_phy.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_CXP_TEST_PHY, clk_gate_cxp_test_phy, + clk_gate_cxp_test_phy_parent, + CLK_SET_RATE_PARENT, + 0x000, 6, 0); + +static const struct clk_hw *clk_gate_cxp_test_eth_phy_parent[] = { + &clk_div_cxp_test_eth_phy.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_CXP_TEST_ETH_PHY, clk_gate_cxp_test_eth_phy, + clk_gate_cxp_test_eth_phy_parent, + CLK_SET_RATE_PARENT, + 0x000, 7, 0); + +static const struct clk_hw *clk_gate_pcie_1g_parent[] = { + &clk_div_pcie_1g.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_PCIE_1G, clk_gate_pcie_1g, + clk_gate_pcie_1g_parent, + CLK_SET_RATE_PARENT, + 0x008, 15, 0); + +static const struct clk_hw *clk_gate_c2c0_test_phy_parent[] = { + &clk_div_c2c0_test_phy.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_C2C0_TEST_PHY, clk_gate_c2c0_test_phy, + clk_gate_c2c0_test_phy_parent, + CLK_SET_RATE_PARENT, + 0x000, 4, 0); + +static const struct clk_hw *clk_gate_c2c1_test_phy_parent[] = { + &clk_div_c2c1_test_phy.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_C2C1_TEST_PHY, clk_gate_c2c1_test_phy, + clk_gate_c2c1_test_phy_parent, + CLK_SET_RATE_PARENT, + 0x000, 5, 0); + +static const struct clk_hw *clk_gate_uart_500m_parent[] = { + &clk_div_uart_500m.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_UART_500M, clk_gate_uart_500m, + clk_gate_uart_500m_parent, + CLK_SET_RATE_PARENT, + 0x004, 1, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_UART, clk_gate_apb_uart, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 2, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_SPI, clk_gate_apb_spi, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 22, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AHB_SPIFMC, clk_gate_ahb_spifmc, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT, + 0x004, 5, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_I2C, clk_gate_apb_i2c, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 23, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AXI_DBG_I2C, clk_gate_axi_dbg_i2c, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 3, 0); + +static const struct clk_hw *clk_gate_gpio_db_parent[] = { + &clk_div_gpio_db.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_GPIO_DB, clk_gate_gpio_db, + clk_gate_gpio_db_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 21, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_GPIO_INTR, clk_gate_apb_gpio_intr, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 20, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_GPIO, clk_gate_apb_gpio, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 19, 0); + +static const struct clk_hw *clk_gate_sd_parent[] = { + &clk_div_sd.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_SD, clk_gate_sd, + clk_gate_sd_parent, + CLK_SET_RATE_PARENT, + 0x008, 3, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AXI_SD, clk_gate_axi_sd, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x008, 2, 0); + +static const struct clk_hw *clk_gate_sd_100k_parent[] = { + &clk_div_sd_100k.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_SD_100K, clk_gate_sd_100k, + clk_gate_sd_100k_parent, + CLK_SET_RATE_PARENT, + 0x008, 4, 0); + +static const struct clk_hw *clk_gate_emmc_parent[] = { + &clk_div_emmc.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_EMMC, clk_gate_emmc, + clk_gate_emmc_parent, + CLK_SET_RATE_PARENT, + 0x008, 0, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AXI_EMMC, clk_gate_axi_emmc, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 31, 0); + +static const struct clk_hw *clk_gate_emmc_100k_parent[] = { + &clk_div_emmc_100k.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_EMMC_100K, clk_gate_emmc_100k, + clk_gate_emmc_100k_parent, + CLK_SET_RATE_PARENT, + 0x008, 1, 0); + +static const struct clk_hw *clk_gate_efuse_parent[] = { + &clk_div_efuse.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_EFUSE, clk_gate_efuse, + clk_gate_efuse_parent, + CLK_SET_RATE_PARENT, + 0x004, 17, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_EFUSE, clk_gate_apb_efuse, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT, + 0x004, 18, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_SYSDMA_AXI, clk_gate_sysdma_axi, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 0, 0); + +static const struct clk_hw *clk_gate_tx_eth0_parent[] = { + &clk_div_tx_eth0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_TX_ETH0, clk_gate_tx_eth0, + clk_gate_tx_eth0_parent, + CLK_SET_RATE_PARENT, + 0x004, 27, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AXI_ETH0, clk_gate_axi_eth0, + clk_div_top_axi_hsperi_parent, + CLK_SET_RATE_PARENT, + 0x004, 28, 0); + +static const struct clk_hw *clk_gate_ptp_ref_i_eth0_parent[] = { + &clk_div_ptp_ref_i_eth0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_PTP_REF_I_ETH0, clk_gate_ptp_ref_i_eth0, + clk_gate_ptp_ref_i_eth0_parent, + CLK_SET_RATE_PARENT, + 0x004, 29, 0); + +static const struct clk_hw *clk_gate_ref_eth0_parent[] = { + &clk_div_ref_eth0.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_REF_ETH0, clk_gate_ref_eth0, + clk_gate_ref_eth0_parent, + CLK_SET_RATE_PARENT, + 0x004, 30, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_RTC, clk_gate_apb_rtc, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 26, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_PWM, clk_gate_apb_pwm, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT, + 0x004, 25, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_APB_WDT, clk_gate_apb_wdt, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT, + 0x004, 24, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AXI_SRAM, clk_gate_axi_sram, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 6, 0); + +static DEFINE_SG2044_GATE(CLK_GATE_AHB_ROM, clk_gate_ahb_rom, + clk_div_top_axi0_parent, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + 0x004, 4, 0); + +static const struct clk_hw *clk_gate_pka_parent[] = { + &clk_div_pka.common.hw, +}; + +static DEFINE_SG2044_GATE(CLK_GATE_PKA, clk_gate_pka, + clk_gate_pka_parent, + CLK_SET_RATE_PARENT, + 0x004, 16, 0); + +static struct sg2044_clk_common * const sg2044_div_commons[] = { + &clk_div_ap_sys_fixed.common, + &clk_div_ap_sys_main.common, + &clk_div_rp_sys_fixed.common, + &clk_div_rp_sys_main.common, + &clk_div_tpu_sys_fixed.common, + &clk_div_tpu_sys_main.common, + &clk_div_noc_sys_fixed.common, + &clk_div_noc_sys_main.common, + &clk_div_vc_src0_fixed.common, + &clk_div_vc_src0_main.common, + &clk_div_vc_src1_fixed.common, + &clk_div_vc_src1_main.common, + &clk_div_cxp_mac_fixed.common, + &clk_div_cxp_mac_main.common, + &clk_div_ddr0_fixed.common, + &clk_div_ddr0_main.common, + &clk_div_ddr1_fixed.common, + &clk_div_ddr1_main.common, + &clk_div_ddr2_fixed.common, + &clk_div_ddr2_main.common, + &clk_div_ddr3_fixed.common, + &clk_div_ddr3_main.common, + &clk_div_ddr4_fixed.common, + &clk_div_ddr4_main.common, + &clk_div_ddr5_fixed.common, + &clk_div_ddr5_main.common, + &clk_div_ddr6_fixed.common, + &clk_div_ddr6_main.common, + &clk_div_ddr7_fixed.common, + &clk_div_ddr7_main.common, + &clk_div_top_50m.common, + &clk_div_top_axi0.common, + &clk_div_top_axi_hsperi.common, + &clk_div_timer0.common, + &clk_div_timer1.common, + &clk_div_timer2.common, + &clk_div_timer3.common, + &clk_div_timer4.common, + &clk_div_timer5.common, + &clk_div_timer6.common, + &clk_div_timer7.common, + &clk_div_cxp_test_phy.common, + &clk_div_cxp_test_eth_phy.common, + &clk_div_c2c0_test_phy.common, + &clk_div_c2c1_test_phy.common, + &clk_div_pcie_1g.common, + &clk_div_uart_500m.common, + &clk_div_gpio_db.common, + &clk_div_sd.common, + &clk_div_sd_100k.common, + &clk_div_emmc.common, + &clk_div_emmc_100k.common, + &clk_div_efuse.common, + &clk_div_tx_eth0.common, + &clk_div_ptp_ref_i_eth0.common, + &clk_div_ref_eth0.common, + &clk_div_pka.common, +}; + +static struct sg2044_clk_common * const sg2044_mux_commons[] = { + &clk_mux_ddr0.common, + &clk_mux_ddr1.common, + &clk_mux_ddr2.common, + &clk_mux_ddr3.common, + &clk_mux_ddr4.common, + &clk_mux_ddr5.common, + &clk_mux_ddr6.common, + &clk_mux_ddr7.common, + &clk_mux_noc_sys.common, + &clk_mux_tpu_sys.common, + &clk_mux_rp_sys.common, + &clk_mux_ap_sys.common, + &clk_mux_vc_src0.common, + &clk_mux_vc_src1.common, + &clk_mux_cxp_mac.common, +}; + +static struct sg2044_clk_common * const sg2044_gate_commons[] = { + &clk_gate_ap_sys.common, + &clk_gate_rp_sys.common, + &clk_gate_tpu_sys.common, + &clk_gate_noc_sys.common, + &clk_gate_vc_src0.common, + &clk_gate_vc_src1.common, + &clk_gate_ddr0.common, + &clk_gate_ddr1.common, + &clk_gate_ddr2.common, + &clk_gate_ddr3.common, + &clk_gate_ddr4.common, + &clk_gate_ddr5.common, + &clk_gate_ddr6.common, + &clk_gate_ddr7.common, + &clk_gate_top_50m.common, + &clk_gate_sc_rx.common, + &clk_gate_sc_rx_x0y1.common, + &clk_gate_top_axi0.common, + &clk_gate_intc0.common, + &clk_gate_intc1.common, + &clk_gate_intc2.common, + &clk_gate_intc3.common, + &clk_gate_mailbox0.common, + &clk_gate_mailbox1.common, + &clk_gate_mailbox2.common, + &clk_gate_mailbox3.common, + &clk_gate_top_axi_hsperi.common, + &clk_gate_apb_timer.common, + &clk_gate_timer0.common, + &clk_gate_timer1.common, + &clk_gate_timer2.common, + &clk_gate_timer3.common, + &clk_gate_timer4.common, + &clk_gate_timer5.common, + &clk_gate_timer6.common, + &clk_gate_timer7.common, + &clk_gate_cxp_cfg.common, + &clk_gate_cxp_mac.common, + &clk_gate_cxp_test_phy.common, + &clk_gate_cxp_test_eth_phy.common, + &clk_gate_pcie_1g.common, + &clk_gate_c2c0_test_phy.common, + &clk_gate_c2c1_test_phy.common, + &clk_gate_uart_500m.common, + &clk_gate_apb_uart.common, + &clk_gate_apb_spi.common, + &clk_gate_ahb_spifmc.common, + &clk_gate_apb_i2c.common, + &clk_gate_axi_dbg_i2c.common, + &clk_gate_gpio_db.common, + &clk_gate_apb_gpio_intr.common, + &clk_gate_apb_gpio.common, + &clk_gate_sd.common, + &clk_gate_axi_sd.common, + &clk_gate_sd_100k.common, + &clk_gate_emmc.common, + &clk_gate_axi_emmc.common, + &clk_gate_emmc_100k.common, + &clk_gate_efuse.common, + &clk_gate_apb_efuse.common, + &clk_gate_sysdma_axi.common, + &clk_gate_tx_eth0.common, + &clk_gate_axi_eth0.common, + &clk_gate_ptp_ref_i_eth0.common, + &clk_gate_ref_eth0.common, + &clk_gate_apb_rtc.common, + &clk_gate_apb_pwm.common, + &clk_gate_apb_wdt.common, + &clk_gate_axi_sram.common, + &clk_gate_ahb_rom.common, + &clk_gate_pka.common, +}; + +static void sg2044_clk_fix_init_parent(struct clk_hw **pdata, + const struct clk_init_data *init, + struct clk_hw_onecell_data *data) +{ + u8 i; + const struct clk_hw *hw; + const struct sg2044_clk_common *common; + + for (i = 0; i < init->num_parents; i++) { + hw = init->parent_hws[i]; + common = hw_to_sg2044_clk_common(hw); + + WARN(!data->hws[common->id], "clk %u is not register\n", + common->id); + pdata[i] = data->hws[common->id]; + } +} + +static int sg2044_clk_init_ctrl(struct device *dev, void __iomem *reg, + struct sg2044_clk_ctrl *ctrl, + const struct sg2044_clk_desc_data *desc) +{ + int ret, i; + struct clk_hw *hw; + + spin_lock_init(&ctrl->lock); + + for (i = 0; i < desc->num_div; i++) { + struct sg2044_clk_common *common = desc->div[i]; + + common->lock = &ctrl->lock; + common->base = reg; + + ret = devm_clk_hw_register(dev, &common->hw); + if (ret) + return ret; + + ctrl->data.hws[common->id] = &common->hw; + } + + for (i = 0; i < desc->num_mux; i++) { + struct sg2044_clk_common *common = desc->mux[i]; + struct sg2044_mux *mux = hw_to_sg2044_mux(&common->hw); + const struct clk_init_data *init = common->hw.init; + + common->lock = &ctrl->lock; + common->base = reg; + + hw = devm_clk_hw_register_mux_parent_data_table(dev, + init->name, + init->parent_data, + init->num_parents, + init->flags, + reg + mux->mux.offset, + mux->mux.shift, + 1, + mux->mux.flags, + mux->mux.table, + &ctrl->lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + if (!(mux->mux.flags & CLK_MUX_READ_ONLY)) { + mux->nb.notifier_call = sg2044_mux_notifier_cb; + ret = devm_clk_notifier_register(dev, hw->clk, + &mux->nb); + if (ret < 0) + return dev_err_probe(dev, ret, + "%s: failed to register notifier\n", + clk_hw_get_name(hw)); + } + + ctrl->data.hws[common->id] = hw; + } + + for (i = 0; i < desc->num_gate; i++) { + struct sg2044_clk_common *common = desc->gate[i]; + struct sg2044_gate *gate = hw_to_sg2044_gate(&common->hw); + const struct clk_init_data *init = common->hw.init; + struct clk_hw *parent_hws[1] = { }; + + sg2044_clk_fix_init_parent(parent_hws, init, &ctrl->data); + common->lock = &ctrl->lock; + common->base = reg; + + hw = devm_clk_hw_register_gate_parent_hw(dev, init->name, + parent_hws[0], + init->flags, + reg + gate->gate.offset, + gate->gate.shift, + gate->gate.flags, + &ctrl->lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + ctrl->data.hws[common->id] = hw; + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &ctrl->data); +} + +static int sg2044_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sg2044_clk_ctrl *ctrl; + const struct sg2044_clk_desc_data *desc; + void __iomem *reg; + u32 num_clks; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + desc = device_get_match_data(dev); + if (!desc) + return dev_err_probe(dev, -EINVAL, "no match data for platform\n"); + + num_clks = desc->num_div + desc->num_gate + desc->num_mux; + + ctrl = devm_kzalloc(dev, struct_size(ctrl, data.hws, num_clks), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->data.num = num_clks; + + return sg2044_clk_init_ctrl(dev, reg, ctrl, desc); +} + +static const struct sg2044_clk_desc_data sg2044_clk_desc_data = { + .div = sg2044_div_commons, + .mux = sg2044_mux_commons, + .gate = sg2044_gate_commons, + .num_div = ARRAY_SIZE(sg2044_div_commons), + .num_mux = ARRAY_SIZE(sg2044_mux_commons), + .num_gate = ARRAY_SIZE(sg2044_gate_commons), +}; + +static const struct of_device_id sg2044_clk_match[] = { + { .compatible = "sophgo,sg2044-clk", .data = &sg2044_clk_desc_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sg2044_clk_match); + +static struct platform_driver sg2044_clk_driver = { + .probe = sg2044_clk_probe, + .driver = { + .name = "sg2044-clk", + .of_match_table = sg2044_clk_match, + }, +}; +module_platform_driver(sg2044_clk_driver); + +MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>"); +MODULE_DESCRIPTION("Sophgo SG2044 clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c index 4c9555fc6184..ebfb1d59401d 100644 --- a/drivers/clk/thead/clk-th1520-ap.c +++ b/drivers/clk/thead/clk-th1520-ap.c @@ -847,6 +847,67 @@ static CCU_GATE(CLK_SRAM1, sram1_clk, "sram1", axi_aclk_pd, 0x20c, BIT(3), 0); static CCU_GATE(CLK_SRAM2, sram2_clk, "sram2", axi_aclk_pd, 0x20c, BIT(2), 0); static CCU_GATE(CLK_SRAM3, sram3_clk, "sram3", axi_aclk_pd, 0x20c, BIT(1), 0); +static CCU_GATE(CLK_AXI4_VO_ACLK, axi4_vo_aclk, "axi4-vo-aclk", + video_pll_clk_pd, 0x0, BIT(0), 0); +static CCU_GATE(CLK_GPU_CORE, gpu_core_clk, "gpu-core-clk", video_pll_clk_pd, + 0x0, BIT(3), 0); +static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", + video_pll_clk_pd, 0x0, BIT(4), 0); +static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", + video_pll_clk_pd, 0x0, BIT(5), 0); +static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", + video_pll_clk_pd, 0x0, BIT(6), 0); +static CCU_GATE(CLK_DPU_HCLK, dpu_hclk, "dpu-hclk", video_pll_clk_pd, 0x0, + BIT(7), 0); +static CCU_GATE(CLK_DPU_ACLK, dpu_aclk, "dpu-aclk", video_pll_clk_pd, 0x0, + BIT(8), 0); +static CCU_GATE(CLK_DPU_CCLK, dpu_cclk, "dpu-cclk", video_pll_clk_pd, 0x0, + BIT(9), 0); +static CCU_GATE(CLK_HDMI_SFR, hdmi_sfr_clk, "hdmi-sfr-clk", video_pll_clk_pd, + 0x0, BIT(10), 0); +static CCU_GATE(CLK_HDMI_PCLK, hdmi_pclk, "hdmi-pclk", video_pll_clk_pd, 0x0, + BIT(11), 0); +static CCU_GATE(CLK_HDMI_CEC, hdmi_cec_clk, "hdmi-cec-clk", video_pll_clk_pd, + 0x0, BIT(12), 0); +static CCU_GATE(CLK_MIPI_DSI0_PCLK, mipi_dsi0_pclk, "mipi-dsi0-pclk", + video_pll_clk_pd, 0x0, BIT(13), 0); +static CCU_GATE(CLK_MIPI_DSI1_PCLK, mipi_dsi1_pclk, "mipi-dsi1-pclk", + video_pll_clk_pd, 0x0, BIT(14), 0); +static CCU_GATE(CLK_MIPI_DSI0_CFG, mipi_dsi0_cfg_clk, "mipi-dsi0-cfg-clk", + video_pll_clk_pd, 0x0, BIT(15), 0); +static CCU_GATE(CLK_MIPI_DSI1_CFG, mipi_dsi1_cfg_clk, "mipi-dsi1-cfg-clk", + video_pll_clk_pd, 0x0, BIT(16), 0); +static CCU_GATE(CLK_MIPI_DSI0_REFCLK, mipi_dsi0_refclk, "mipi-dsi0-refclk", + video_pll_clk_pd, 0x0, BIT(17), 0); +static CCU_GATE(CLK_MIPI_DSI1_REFCLK, mipi_dsi1_refclk, "mipi-dsi1-refclk", + video_pll_clk_pd, 0x0, BIT(18), 0); +static CCU_GATE(CLK_HDMI_I2S, hdmi_i2s_clk, "hdmi-i2s-clk", video_pll_clk_pd, + 0x0, BIT(19), 0); +static CCU_GATE(CLK_X2H_DPU1_ACLK, x2h_dpu1_aclk, "x2h-dpu1-aclk", + video_pll_clk_pd, 0x0, BIT(20), 0); +static CCU_GATE(CLK_X2H_DPU_ACLK, x2h_dpu_aclk, "x2h-dpu-aclk", + video_pll_clk_pd, 0x0, BIT(21), 0); +static CCU_GATE(CLK_AXI4_VO_PCLK, axi4_vo_pclk, "axi4-vo-pclk", + video_pll_clk_pd, 0x0, BIT(22), 0); +static CCU_GATE(CLK_IOPMP_VOSYS_DPU_PCLK, iopmp_vosys_dpu_pclk, + "iopmp-vosys-dpu-pclk", video_pll_clk_pd, 0x0, BIT(23), 0); +static CCU_GATE(CLK_IOPMP_VOSYS_DPU1_PCLK, iopmp_vosys_dpu1_pclk, + "iopmp-vosys-dpu1-pclk", video_pll_clk_pd, 0x0, BIT(24), 0); +static CCU_GATE(CLK_IOPMP_VOSYS_GPU_PCLK, iopmp_vosys_gpu_pclk, + "iopmp-vosys-gpu-pclk", video_pll_clk_pd, 0x0, BIT(25), 0); +static CCU_GATE(CLK_IOPMP_DPU1_ACLK, iopmp_dpu1_aclk, "iopmp-dpu1-aclk", + video_pll_clk_pd, 0x0, BIT(27), 0); +static CCU_GATE(CLK_IOPMP_DPU_ACLK, iopmp_dpu_aclk, "iopmp-dpu-aclk", + video_pll_clk_pd, 0x0, BIT(28), 0); +static CCU_GATE(CLK_IOPMP_GPU_ACLK, iopmp_gpu_aclk, "iopmp-gpu-aclk", + video_pll_clk_pd, 0x0, BIT(29), 0); +static CCU_GATE(CLK_MIPIDSI0_PIXCLK, mipi_dsi0_pixclk, "mipi-dsi0-pixclk", + video_pll_clk_pd, 0x0, BIT(30), 0); +static CCU_GATE(CLK_MIPIDSI1_PIXCLK, mipi_dsi1_pixclk, "mipi-dsi1-pixclk", + video_pll_clk_pd, 0x0, BIT(31), 0); +static CCU_GATE(CLK_HDMI_PIXCLK, hdmi_pixclk, "hdmi-pixclk", video_pll_clk_pd, + 0x4, BIT(0), 0); + static CLK_FIXED_FACTOR_HW(gmac_pll_clk_100m, "gmac-pll-clk-100m", &gmac_pll_clk.common.hw, 10, 1, 0); @@ -963,7 +1024,38 @@ static struct ccu_common *th1520_gate_clks[] = { &sram3_clk.common, }; -#define NR_CLKS (CLK_UART_SCLK + 1) +static struct ccu_common *th1520_vo_gate_clks[] = { + &axi4_vo_aclk.common, + &gpu_core_clk.common, + &gpu_cfg_aclk.common, + &dpu0_pixelclk.common, + &dpu1_pixelclk.common, + &dpu_hclk.common, + &dpu_aclk.common, + &dpu_cclk.common, + &hdmi_sfr_clk.common, + &hdmi_pclk.common, + &hdmi_cec_clk.common, + &mipi_dsi0_pclk.common, + &mipi_dsi1_pclk.common, + &mipi_dsi0_cfg_clk.common, + &mipi_dsi1_cfg_clk.common, + &mipi_dsi0_refclk.common, + &mipi_dsi1_refclk.common, + &hdmi_i2s_clk.common, + &x2h_dpu1_aclk.common, + &x2h_dpu_aclk.common, + &axi4_vo_pclk.common, + &iopmp_vosys_dpu_pclk.common, + &iopmp_vosys_dpu1_pclk.common, + &iopmp_vosys_gpu_pclk.common, + &iopmp_dpu1_aclk.common, + &iopmp_dpu_aclk.common, + &iopmp_gpu_aclk.common, + &mipi_dsi0_pixclk.common, + &mipi_dsi1_pixclk.common, + &hdmi_pixclk.common +}; static const struct regmap_config th1520_clk_regmap_config = { .reg_bits = 32, @@ -972,8 +1064,44 @@ static const struct regmap_config th1520_clk_regmap_config = { .fast_io = true, }; +struct th1520_plat_data { + struct ccu_common **th1520_pll_clks; + struct ccu_common **th1520_div_clks; + struct ccu_common **th1520_mux_clks; + struct ccu_common **th1520_gate_clks; + + int nr_clks; + int nr_pll_clks; + int nr_div_clks; + int nr_mux_clks; + int nr_gate_clks; +}; + +static const struct th1520_plat_data th1520_ap_platdata = { + .th1520_pll_clks = th1520_pll_clks, + .th1520_div_clks = th1520_div_clks, + .th1520_mux_clks = th1520_mux_clks, + .th1520_gate_clks = th1520_gate_clks, + + .nr_clks = CLK_UART_SCLK + 1, + + .nr_pll_clks = ARRAY_SIZE(th1520_pll_clks), + .nr_div_clks = ARRAY_SIZE(th1520_div_clks), + .nr_mux_clks = ARRAY_SIZE(th1520_mux_clks), + .nr_gate_clks = ARRAY_SIZE(th1520_gate_clks), +}; + +static const struct th1520_plat_data th1520_vo_platdata = { + .th1520_gate_clks = th1520_vo_gate_clks, + + .nr_clks = CLK_HDMI_PIXCLK + 1, + + .nr_gate_clks = ARRAY_SIZE(th1520_vo_gate_clks), +}; + static int th1520_clk_probe(struct platform_device *pdev) { + const struct th1520_plat_data *plat_data; struct device *dev = &pdev->dev; struct clk_hw_onecell_data *priv; @@ -982,11 +1110,16 @@ static int th1520_clk_probe(struct platform_device *pdev) struct clk_hw *hw; int ret, i; - priv = devm_kzalloc(dev, struct_size(priv, hws, NR_CLKS), GFP_KERNEL); + plat_data = device_get_match_data(&pdev->dev); + if (!plat_data) + return dev_err_probe(&pdev->dev, -ENODEV, + "No device match data found\n"); + + priv = devm_kzalloc(dev, struct_size(priv, hws, plat_data->nr_clks), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->num = NR_CLKS; + priv->num = plat_data->nr_clks; base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -996,35 +1129,35 @@ static int th1520_clk_probe(struct platform_device *pdev) if (IS_ERR(map)) return PTR_ERR(map); - for (i = 0; i < ARRAY_SIZE(th1520_pll_clks); i++) { - struct ccu_pll *cp = hw_to_ccu_pll(&th1520_pll_clks[i]->hw); + for (i = 0; i < plat_data->nr_pll_clks; i++) { + struct ccu_pll *cp = hw_to_ccu_pll(&plat_data->th1520_pll_clks[i]->hw); - th1520_pll_clks[i]->map = map; + plat_data->th1520_pll_clks[i]->map = map; - ret = devm_clk_hw_register(dev, &th1520_pll_clks[i]->hw); + ret = devm_clk_hw_register(dev, &plat_data->th1520_pll_clks[i]->hw); if (ret) return ret; priv->hws[cp->common.clkid] = &cp->common.hw; } - for (i = 0; i < ARRAY_SIZE(th1520_div_clks); i++) { - struct ccu_div *cd = hw_to_ccu_div(&th1520_div_clks[i]->hw); + for (i = 0; i < plat_data->nr_div_clks; i++) { + struct ccu_div *cd = hw_to_ccu_div(&plat_data->th1520_div_clks[i]->hw); - th1520_div_clks[i]->map = map; + plat_data->th1520_div_clks[i]->map = map; - ret = devm_clk_hw_register(dev, &th1520_div_clks[i]->hw); + ret = devm_clk_hw_register(dev, &plat_data->th1520_div_clks[i]->hw); if (ret) return ret; priv->hws[cd->common.clkid] = &cd->common.hw; } - for (i = 0; i < ARRAY_SIZE(th1520_mux_clks); i++) { - struct ccu_mux *cm = hw_to_ccu_mux(&th1520_mux_clks[i]->hw); + for (i = 0; i < plat_data->nr_mux_clks; i++) { + struct ccu_mux *cm = hw_to_ccu_mux(&plat_data->th1520_mux_clks[i]->hw); const struct clk_init_data *init = cm->common.hw.init; - th1520_mux_clks[i]->map = map; + plat_data->th1520_mux_clks[i]->map = map; hw = devm_clk_hw_register_mux_parent_data_table(dev, init->name, init->parent_data, @@ -1040,10 +1173,10 @@ static int th1520_clk_probe(struct platform_device *pdev) priv->hws[cm->common.clkid] = hw; } - for (i = 0; i < ARRAY_SIZE(th1520_gate_clks); i++) { - struct ccu_gate *cg = hw_to_ccu_gate(&th1520_gate_clks[i]->hw); + for (i = 0; i < plat_data->nr_gate_clks; i++) { + struct ccu_gate *cg = hw_to_ccu_gate(&plat_data->th1520_gate_clks[i]->hw); - th1520_gate_clks[i]->map = map; + plat_data->th1520_gate_clks[i]->map = map; hw = devm_clk_hw_register_gate_parent_data(dev, cg->common.hw.init->name, @@ -1057,19 +1190,21 @@ static int th1520_clk_probe(struct platform_device *pdev) priv->hws[cg->common.clkid] = hw; } - ret = devm_clk_hw_register(dev, &osc12m_clk.hw); - if (ret) - return ret; - priv->hws[CLK_OSC12M] = &osc12m_clk.hw; + if (plat_data == &th1520_ap_platdata) { + ret = devm_clk_hw_register(dev, &osc12m_clk.hw); + if (ret) + return ret; + priv->hws[CLK_OSC12M] = &osc12m_clk.hw; - ret = devm_clk_hw_register(dev, &gmac_pll_clk_100m.hw); - if (ret) - return ret; - priv->hws[CLK_PLL_GMAC_100M] = &gmac_pll_clk_100m.hw; + ret = devm_clk_hw_register(dev, &gmac_pll_clk_100m.hw); + if (ret) + return ret; + priv->hws[CLK_PLL_GMAC_100M] = &gmac_pll_clk_100m.hw; - ret = devm_clk_hw_register(dev, &emmc_sdio_ref_clk.hw); - if (ret) - return ret; + ret = devm_clk_hw_register(dev, &emmc_sdio_ref_clk.hw); + if (ret) + return ret; + } ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv); if (ret) @@ -1081,6 +1216,11 @@ static int th1520_clk_probe(struct platform_device *pdev) static const struct of_device_id th1520_clk_match[] = { { .compatible = "thead,th1520-clk-ap", + .data = &th1520_ap_platdata, + }, + { + .compatible = "thead,th1520-clk-vo", + .data = &th1520_vo_platdata, }, { /* sentinel */ }, }; diff --git a/include/dt-bindings/clock/samsung,exynosautov920.h b/include/dt-bindings/clock/samsung,exynosautov920.h index 0c681f2ba3d0..5e6896e9627f 100644 --- a/include/dt-bindings/clock/samsung,exynosautov920.h +++ b/include/dt-bindings/clock/samsung,exynosautov920.h @@ -162,6 +162,57 @@ #define DOUT_CLKCMU_TAA_NOC 146 #define DOUT_TCXO_DIV2 147 +/* CMU_CPUCL0 */ +#define CLK_FOUT_CPUCL0_PLL 1 + +#define CLK_MOUT_PLL_CPUCL0 2 +#define CLK_MOUT_CPUCL0_CLUSTER_USER 3 +#define CLK_MOUT_CPUCL0_DBG_USER 4 +#define CLK_MOUT_CPUCL0_SWITCH_USER 5 +#define CLK_MOUT_CPUCL0_CLUSTER 6 +#define CLK_MOUT_CPUCL0_CORE 7 + +#define CLK_DOUT_CLUSTER0_ACLK 8 +#define CLK_DOUT_CLUSTER0_ATCLK 9 +#define CLK_DOUT_CLUSTER0_MPCLK 10 +#define CLK_DOUT_CLUSTER0_PCLK 11 +#define CLK_DOUT_CLUSTER0_PERIPHCLK 12 +#define CLK_DOUT_CPUCL0_DBG_NOC 13 +#define CLK_DOUT_CPUCL0_DBG_PCLKDBG 14 +#define CLK_DOUT_CPUCL0_NOCP 15 + +/* CMU_CPUCL1 */ +#define CLK_FOUT_CPUCL1_PLL 1 + +#define CLK_MOUT_PLL_CPUCL1 2 +#define CLK_MOUT_CPUCL1_CLUSTER_USER 3 +#define CLK_MOUT_CPUCL1_SWITCH_USER 4 +#define CLK_MOUT_CPUCL1_CLUSTER 5 +#define CLK_MOUT_CPUCL1_CORE 6 + +#define CLK_DOUT_CLUSTER1_ACLK 7 +#define CLK_DOUT_CLUSTER1_ATCLK 8 +#define CLK_DOUT_CLUSTER1_MPCLK 9 +#define CLK_DOUT_CLUSTER1_PCLK 10 +#define CLK_DOUT_CLUSTER1_PERIPHCLK 11 +#define CLK_DOUT_CPUCL1_NOCP 12 + +/* CMU_CPUCL2 */ +#define CLK_FOUT_CPUCL2_PLL 1 + +#define CLK_MOUT_PLL_CPUCL2 2 +#define CLK_MOUT_CPUCL2_CLUSTER_USER 3 +#define CLK_MOUT_CPUCL2_SWITCH_USER 4 +#define CLK_MOUT_CPUCL2_CLUSTER 5 +#define CLK_MOUT_CPUCL2_CORE 6 + +#define CLK_DOUT_CLUSTER2_ACLK 7 +#define CLK_DOUT_CLUSTER2_ATCLK 8 +#define CLK_DOUT_CLUSTER2_MPCLK 9 +#define CLK_DOUT_CLUSTER2_PCLK 10 +#define CLK_DOUT_CLUSTER2_PERIPHCLK 11 +#define CLK_DOUT_CPUCL2_NOCP 12 + /* CMU_PERIC0 */ #define CLK_MOUT_PERIC0_IP_USER 1 #define CLK_MOUT_PERIC0_NOC_USER 2 diff --git a/include/dt-bindings/clock/sophgo,sg2044-clk.h b/include/dt-bindings/clock/sophgo,sg2044-clk.h new file mode 100644 index 000000000000..d9adca42548e --- /dev/null +++ b/include/dt-bindings/clock/sophgo,sg2044-clk.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2024 Inochi Amaoto <inochiama@gmail.com> + */ + +#ifndef __DT_BINDINGS_SOPHGO_SG2044_CLK_H__ +#define __DT_BINDINGS_SOPHGO_SG2044_CLK_H__ + +#define CLK_DIV_AP_SYS_FIXED 0 +#define CLK_DIV_AP_SYS_MAIN 1 +#define CLK_DIV_RP_SYS_FIXED 2 +#define CLK_DIV_RP_SYS_MAIN 3 +#define CLK_DIV_TPU_SYS_FIXED 4 +#define CLK_DIV_TPU_SYS_MAIN 5 +#define CLK_DIV_NOC_SYS_FIXED 6 +#define CLK_DIV_NOC_SYS_MAIN 7 +#define CLK_DIV_VC_SRC0_FIXED 8 +#define CLK_DIV_VC_SRC0_MAIN 9 +#define CLK_DIV_VC_SRC1_FIXED 10 +#define CLK_DIV_VC_SRC1_MAIN 11 +#define CLK_DIV_CXP_MAC_FIXED 12 +#define CLK_DIV_CXP_MAC_MAIN 13 +#define CLK_DIV_DDR0_FIXED 14 +#define CLK_DIV_DDR0_MAIN 15 +#define CLK_DIV_DDR1_FIXED 16 +#define CLK_DIV_DDR1_MAIN 17 +#define CLK_DIV_DDR2_FIXED 18 +#define CLK_DIV_DDR2_MAIN 19 +#define CLK_DIV_DDR3_FIXED 20 +#define CLK_DIV_DDR3_MAIN 21 +#define CLK_DIV_DDR4_FIXED 22 +#define CLK_DIV_DDR4_MAIN 23 +#define CLK_DIV_DDR5_FIXED 24 +#define CLK_DIV_DDR5_MAIN 25 +#define CLK_DIV_DDR6_FIXED 26 +#define CLK_DIV_DDR6_MAIN 27 +#define CLK_DIV_DDR7_FIXED 28 +#define CLK_DIV_DDR7_MAIN 29 +#define CLK_DIV_TOP_50M 30 +#define CLK_DIV_TOP_AXI0 31 +#define CLK_DIV_TOP_AXI_HSPERI 32 +#define CLK_DIV_TIMER0 33 +#define CLK_DIV_TIMER1 34 +#define CLK_DIV_TIMER2 35 +#define CLK_DIV_TIMER3 36 +#define CLK_DIV_TIMER4 37 +#define CLK_DIV_TIMER5 38 +#define CLK_DIV_TIMER6 39 +#define CLK_DIV_TIMER7 40 +#define CLK_DIV_CXP_TEST_PHY 41 +#define CLK_DIV_CXP_TEST_ETH_PHY 42 +#define CLK_DIV_C2C0_TEST_PHY 43 +#define CLK_DIV_C2C1_TEST_PHY 44 +#define CLK_DIV_PCIE_1G 45 +#define CLK_DIV_UART_500M 46 +#define CLK_DIV_GPIO_DB 47 +#define CLK_DIV_SD 48 +#define CLK_DIV_SD_100K 49 +#define CLK_DIV_EMMC 50 +#define CLK_DIV_EMMC_100K 51 +#define CLK_DIV_EFUSE 52 +#define CLK_DIV_TX_ETH0 53 +#define CLK_DIV_PTP_REF_I_ETH0 54 +#define CLK_DIV_REF_ETH0 55 +#define CLK_DIV_PKA 56 +#define CLK_MUX_DDR0 57 +#define CLK_MUX_DDR1 58 +#define CLK_MUX_DDR2 59 +#define CLK_MUX_DDR3 60 +#define CLK_MUX_DDR4 61 +#define CLK_MUX_DDR5 62 +#define CLK_MUX_DDR6 63 +#define CLK_MUX_DDR7 64 +#define CLK_MUX_NOC_SYS 65 +#define CLK_MUX_TPU_SYS 66 +#define CLK_MUX_RP_SYS 67 +#define CLK_MUX_AP_SYS 68 +#define CLK_MUX_VC_SRC0 69 +#define CLK_MUX_VC_SRC1 70 +#define CLK_MUX_CXP_MAC 71 +#define CLK_GATE_AP_SYS 72 +#define CLK_GATE_RP_SYS 73 +#define CLK_GATE_TPU_SYS 74 +#define CLK_GATE_NOC_SYS 75 +#define CLK_GATE_VC_SRC0 76 +#define CLK_GATE_VC_SRC1 77 +#define CLK_GATE_DDR0 78 +#define CLK_GATE_DDR1 79 +#define CLK_GATE_DDR2 80 +#define CLK_GATE_DDR3 81 +#define CLK_GATE_DDR4 82 +#define CLK_GATE_DDR5 83 +#define CLK_GATE_DDR6 84 +#define CLK_GATE_DDR7 85 +#define CLK_GATE_TOP_50M 86 +#define CLK_GATE_SC_RX 87 +#define CLK_GATE_SC_RX_X0Y1 88 +#define CLK_GATE_TOP_AXI0 89 +#define CLK_GATE_INTC0 90 +#define CLK_GATE_INTC1 91 +#define CLK_GATE_INTC2 92 +#define CLK_GATE_INTC3 93 +#define CLK_GATE_MAILBOX0 94 +#define CLK_GATE_MAILBOX1 95 +#define CLK_GATE_MAILBOX2 96 +#define CLK_GATE_MAILBOX3 97 +#define CLK_GATE_TOP_AXI_HSPERI 98 +#define CLK_GATE_APB_TIMER 99 +#define CLK_GATE_TIMER0 100 +#define CLK_GATE_TIMER1 101 +#define CLK_GATE_TIMER2 102 +#define CLK_GATE_TIMER3 103 +#define CLK_GATE_TIMER4 104 +#define CLK_GATE_TIMER5 105 +#define CLK_GATE_TIMER6 106 +#define CLK_GATE_TIMER7 107 +#define CLK_GATE_CXP_CFG 108 +#define CLK_GATE_CXP_MAC 109 +#define CLK_GATE_CXP_TEST_PHY 110 +#define CLK_GATE_CXP_TEST_ETH_PHY 111 +#define CLK_GATE_PCIE_1G 112 +#define CLK_GATE_C2C0_TEST_PHY 113 +#define CLK_GATE_C2C1_TEST_PHY 114 +#define CLK_GATE_UART_500M 115 +#define CLK_GATE_APB_UART 116 +#define CLK_GATE_APB_SPI 117 +#define CLK_GATE_AHB_SPIFMC 118 +#define CLK_GATE_APB_I2C 119 +#define CLK_GATE_AXI_DBG_I2C 120 +#define CLK_GATE_GPIO_DB 121 +#define CLK_GATE_APB_GPIO_INTR 122 +#define CLK_GATE_APB_GPIO 123 +#define CLK_GATE_SD 124 +#define CLK_GATE_AXI_SD 125 +#define CLK_GATE_SD_100K 126 +#define CLK_GATE_EMMC 127 +#define CLK_GATE_AXI_EMMC 128 +#define CLK_GATE_EMMC_100K 129 +#define CLK_GATE_EFUSE 130 +#define CLK_GATE_APB_EFUSE 131 +#define CLK_GATE_SYSDMA_AXI 132 +#define CLK_GATE_TX_ETH0 133 +#define CLK_GATE_AXI_ETH0 134 +#define CLK_GATE_PTP_REF_I_ETH0 135 +#define CLK_GATE_REF_ETH0 136 +#define CLK_GATE_APB_RTC 137 +#define CLK_GATE_APB_PWM 138 +#define CLK_GATE_APB_WDT 139 +#define CLK_GATE_AXI_SRAM 140 +#define CLK_GATE_AHB_ROM 141 +#define CLK_GATE_PKA 142 + +#endif /* __DT_BINDINGS_SOPHGO_SG2044_CLK_H__ */ diff --git a/include/dt-bindings/clock/sophgo,sg2044-pll.h b/include/dt-bindings/clock/sophgo,sg2044-pll.h new file mode 100644 index 000000000000..817d45e700cc --- /dev/null +++ b/include/dt-bindings/clock/sophgo,sg2044-pll.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Copyright (C) 2024 Inochi Amaoto <inochiama@gmail.com> + */ + +#ifndef __DT_BINDINGS_SOPHGO_SG2044_PLL_H__ +#define __DT_BINDINGS_SOPHGO_SG2044_PLL_H__ + +#define CLK_FPLL0 0 +#define CLK_FPLL1 1 +#define CLK_FPLL2 2 +#define CLK_DPLL0 3 +#define CLK_DPLL1 4 +#define CLK_DPLL2 5 +#define CLK_DPLL3 6 +#define CLK_DPLL4 7 +#define CLK_DPLL5 8 +#define CLK_DPLL6 9 +#define CLK_DPLL7 10 +#define CLK_MPLL0 11 +#define CLK_MPLL1 12 +#define CLK_MPLL2 13 +#define CLK_MPLL3 14 +#define CLK_MPLL4 15 +#define CLK_MPLL5 16 + +#endif /* __DT_BINDINGS_SOPHGO_SG2044_PLL_H__ */ diff --git a/include/dt-bindings/clock/thead,th1520-clk-ap.h b/include/dt-bindings/clock/thead,th1520-clk-ap.h index a199784b3512..09a9aa7b3ab1 100644 --- a/include/dt-bindings/clock/thead,th1520-clk-ap.h +++ b/include/dt-bindings/clock/thead,th1520-clk-ap.h @@ -93,4 +93,38 @@ #define CLK_SRAM3 83 #define CLK_PLL_GMAC_100M 84 #define CLK_UART_SCLK 85 + +/* VO clocks */ +#define CLK_AXI4_VO_ACLK 0 +#define CLK_GPU_MEM 1 +#define CLK_GPU_CORE 2 +#define CLK_GPU_CFG_ACLK 3 +#define CLK_DPU_PIXELCLK0 4 +#define CLK_DPU_PIXELCLK1 5 +#define CLK_DPU_HCLK 6 +#define CLK_DPU_ACLK 7 +#define CLK_DPU_CCLK 8 +#define CLK_HDMI_SFR 9 +#define CLK_HDMI_PCLK 10 +#define CLK_HDMI_CEC 11 +#define CLK_MIPI_DSI0_PCLK 12 +#define CLK_MIPI_DSI1_PCLK 13 +#define CLK_MIPI_DSI0_CFG 14 +#define CLK_MIPI_DSI1_CFG 15 +#define CLK_MIPI_DSI0_REFCLK 16 +#define CLK_MIPI_DSI1_REFCLK 17 +#define CLK_HDMI_I2S 18 +#define CLK_X2H_DPU1_ACLK 19 +#define CLK_X2H_DPU_ACLK 20 +#define CLK_AXI4_VO_PCLK 21 +#define CLK_IOPMP_VOSYS_DPU_PCLK 22 +#define CLK_IOPMP_VOSYS_DPU1_PCLK 23 +#define CLK_IOPMP_VOSYS_GPU_PCLK 24 +#define CLK_IOPMP_DPU1_ACLK 25 +#define CLK_IOPMP_DPU_ACLK 26 +#define CLK_IOPMP_GPU_ACLK 27 +#define CLK_MIPIDSI0_PIXCLK 28 +#define CLK_MIPIDSI1_PIXCLK 29 +#define CLK_HDMI_PIXCLK 30 + #endif |