Merge branches 'clk-ingenic', 'clk-mtk-mux', 'clk-qcom-sdm845-pcie', 'clk-mtk-crit...
[sfrench/cifs-2.6.git] / drivers / clk / mvebu / mv98dx3236.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Marvell MV98DX3236 SoC clocks
4  *
5  * Copyright (C) 2012 Marvell
6  *
7  * Gregory CLEMENT <gregory.clement@free-electrons.com>
8  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
9  * Andrew Lunn <andrew@lunn.ch>
10  *
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/clk-provider.h>
15 #include <linux/io.h>
16 #include <linux/of.h>
17 #include "common.h"
18
19
20 /*
21  * For 98DX4251 Sample At Reset the CPU, DDR and Main PLL clocks are all
22  * defined at the same time
23  *
24  * SAR1[20:18]   : CPU frequency    DDR frequency   MPLL frequency
25  *               0  =  400 MHz      400 MHz         800 MHz
26  *               2  =  667 MHz      667 MHz         2000 MHz
27  *               3  =  800 MHz      800 MHz         1600 MHz
28  *               others reserved.
29  *
30  * For 98DX3236 Sample At Reset the CPU, DDR and Main PLL clocks are all
31  * defined at the same time
32  *
33  * SAR1[20:18]   : CPU frequency    DDR frequency   MPLL frequency
34  *               1  =  667 MHz      667 MHz         2000 MHz
35  *               2  =  400 MHz      400 MHz         400 MHz
36  *               3  =  800 MHz      800 MHz         800 MHz
37  *               5  =  800 MHz      400 MHz         800 MHz
38  *               others reserved.
39  */
40
41 #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT           18
42 #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK      0x7
43
44 static u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar)
45 {
46         /* Tclk = 200MHz, no SaR dependency */
47         return 200000000;
48 }
49
50 static const u32 mv98dx3236_cpu_frequencies[] __initconst = {
51         0,
52         667000000,
53         400000000,
54         800000000,
55         0,
56         800000000,
57         0, 0,
58 };
59
60 static const u32 mv98dx4251_cpu_frequencies[] __initconst = {
61         400000000,
62         0,
63         667000000,
64         800000000,
65         0, 0, 0, 0,
66 };
67
68 static u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar)
69 {
70         u32 cpu_freq = 0;
71         u8 cpu_freq_select = 0;
72
73         cpu_freq_select = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
74                            SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
75
76         if (of_machine_is_compatible("marvell,armadaxp-98dx4251"))
77                 cpu_freq = mv98dx4251_cpu_frequencies[cpu_freq_select];
78         else if (of_machine_is_compatible("marvell,armadaxp-98dx3236"))
79                 cpu_freq = mv98dx3236_cpu_frequencies[cpu_freq_select];
80
81         if (!cpu_freq)
82                 pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
83
84         return cpu_freq;
85 }
86
87 enum {
88         MV98DX3236_CPU_TO_DDR,
89         MV98DX3236_CPU_TO_MPLL
90 };
91
92 static const struct coreclk_ratio mv98dx3236_core_ratios[] __initconst = {
93         { .id = MV98DX3236_CPU_TO_DDR, .name = "ddrclk" },
94         { .id = MV98DX3236_CPU_TO_MPLL, .name = "mpll" },
95 };
96
97 static const int __initconst mv98dx3236_cpu_mpll_ratios[8][2] = {
98         {0, 1}, {3, 1}, {1, 1}, {1, 1},
99         {0, 1}, {1, 1}, {0, 1}, {0, 1},
100 };
101
102 static const int __initconst mv98dx3236_cpu_ddr_ratios[8][2] = {
103         {0, 1}, {1, 1}, {1, 1}, {1, 1},
104         {0, 1}, {1, 2}, {0, 1}, {0, 1},
105 };
106
107 static const int __initconst mv98dx4251_cpu_mpll_ratios[8][2] = {
108         {2, 1}, {0, 1}, {3, 1}, {2, 1},
109         {0, 1}, {0, 1}, {0, 1}, {0, 1},
110 };
111
112 static const int __initconst mv98dx4251_cpu_ddr_ratios[8][2] = {
113         {1, 1}, {0, 1}, {1, 1}, {1, 1},
114         {0, 1}, {0, 1}, {0, 1}, {0, 1},
115 };
116
117 static void __init mv98dx3236_get_clk_ratio(
118         void __iomem *sar, int id, int *mult, int *div)
119 {
120         u32 opt = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
121                 SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
122
123         switch (id) {
124         case MV98DX3236_CPU_TO_DDR:
125                 if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
126                         *mult = mv98dx4251_cpu_ddr_ratios[opt][0];
127                         *div = mv98dx4251_cpu_ddr_ratios[opt][1];
128                 } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
129                         *mult = mv98dx3236_cpu_ddr_ratios[opt][0];
130                         *div = mv98dx3236_cpu_ddr_ratios[opt][1];
131                 }
132                 break;
133         case MV98DX3236_CPU_TO_MPLL:
134                 if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
135                         *mult = mv98dx4251_cpu_mpll_ratios[opt][0];
136                         *div = mv98dx4251_cpu_mpll_ratios[opt][1];
137                 } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
138                         *mult = mv98dx3236_cpu_mpll_ratios[opt][0];
139                         *div = mv98dx3236_cpu_mpll_ratios[opt][1];
140                 }
141                 break;
142         }
143 }
144
145 static const struct coreclk_soc_desc mv98dx3236_core_clocks = {
146         .get_tclk_freq = mv98dx3236_get_tclk_freq,
147         .get_cpu_freq = mv98dx3236_get_cpu_freq,
148         .get_clk_ratio = mv98dx3236_get_clk_ratio,
149         .ratios = mv98dx3236_core_ratios,
150         .num_ratios = ARRAY_SIZE(mv98dx3236_core_ratios),
151 };
152
153
154 /*
155  * Clock Gating Control
156  */
157
158 static const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = {
159         { "ge1", NULL, 3, 0 },
160         { "ge0", NULL, 4, 0 },
161         { "pex00", NULL, 5, 0 },
162         { "sdio", NULL, 17, 0 },
163         { "usb0", NULL, 18, 0 },
164         { "xor0", NULL, 22, 0 },
165         { }
166 };
167
168 static void __init mv98dx3236_clk_init(struct device_node *np)
169 {
170         struct device_node *cgnp =
171                 of_find_compatible_node(NULL, NULL, "marvell,mv98dx3236-gating-clock");
172
173         mvebu_coreclk_setup(np, &mv98dx3236_core_clocks);
174
175         if (cgnp) {
176                 mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc);
177                 of_node_put(cgnp);
178         }
179 }
180 CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init);