Commit | Line | Data |
---|---|---|
b9b8e614 GF |
1 | /* |
2 | * Copyright (C) 2014 STMicroelectronics (R&D) Limited | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | */ | |
10 | ||
11 | /* | |
12 | * Authors: | |
13 | * Stephen Gallimore <stephen.gallimore@st.com>, | |
14 | * Pankaj Dev <pankaj.dev@st.com>. | |
15 | */ | |
16 | ||
17 | #include <linux/slab.h> | |
18 | #include <linux/of_address.h> | |
d5f728ac | 19 | #include <linux/clk.h> |
b9b8e614 | 20 | #include <linux/clk-provider.h> |
fb473862 | 21 | #include <linux/iopoll.h> |
b9b8e614 GF |
22 | |
23 | #include "clkgen.h" | |
24 | ||
25 | static DEFINE_SPINLOCK(clkgena_c32_odf_lock); | |
46a57afd | 26 | DEFINE_SPINLOCK(clkgen_a9_lock); |
b9b8e614 GF |
27 | |
28 | /* | |
29 | * Common PLL configuration register bits for PLL800 and PLL1600 C65 | |
30 | */ | |
31 | #define C65_MDIV_PLL800_MASK (0xff) | |
32 | #define C65_MDIV_PLL1600_MASK (0x7) | |
33 | #define C65_NDIV_MASK (0xff) | |
34 | #define C65_PDIV_MASK (0x7) | |
35 | ||
36 | /* | |
37 | * PLL configuration register bits for PLL3200 C32 | |
38 | */ | |
39 | #define C32_NDIV_MASK (0xff) | |
40 | #define C32_IDF_MASK (0x7) | |
41 | #define C32_ODF_MASK (0x3f) | |
42 | #define C32_LDF_MASK (0x7f) | |
46a57afd | 43 | #define C32_CP_MASK (0x1f) |
b9b8e614 GF |
44 | |
45 | #define C32_MAX_ODFS (4) | |
46 | ||
0829ea5a GF |
47 | /* |
48 | * PLL configuration register bits for PLL4600 C28 | |
49 | */ | |
50 | #define C28_NDIV_MASK (0xff) | |
51 | #define C28_IDF_MASK (0x7) | |
52 | #define C28_ODF_MASK (0x3f) | |
53 | ||
b9b8e614 GF |
54 | struct clkgen_pll_data { |
55 | struct clkgen_field pdn_status; | |
fb473862 | 56 | struct clkgen_field pdn_ctrl; |
b9b8e614 GF |
57 | struct clkgen_field locked_status; |
58 | struct clkgen_field mdiv; | |
59 | struct clkgen_field ndiv; | |
60 | struct clkgen_field pdiv; | |
61 | struct clkgen_field idf; | |
62 | struct clkgen_field ldf; | |
46a57afd | 63 | struct clkgen_field cp; |
b9b8e614 GF |
64 | unsigned int num_odfs; |
65 | struct clkgen_field odf[C32_MAX_ODFS]; | |
66 | struct clkgen_field odf_gate[C32_MAX_ODFS]; | |
46a57afd GF |
67 | bool switch2pll_en; |
68 | struct clkgen_field switch2pll; | |
69 | spinlock_t *lock; | |
b9b8e614 GF |
70 | const struct clk_ops *ops; |
71 | }; | |
72 | ||
73 | static const struct clk_ops st_pll1600c65_ops; | |
74 | static const struct clk_ops st_pll800c65_ops; | |
75 | static const struct clk_ops stm_pll3200c32_ops; | |
46a57afd | 76 | static const struct clk_ops stm_pll3200c32_a9_ops; |
b9b8e614 | 77 | static const struct clk_ops st_pll1200c32_ops; |
0829ea5a | 78 | static const struct clk_ops stm_pll4600c28_ops; |
b9b8e614 | 79 | |
dc4febef | 80 | static const struct clkgen_pll_data st_pll1600c65_ax = { |
b9b8e614 | 81 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 82 | .pdn_ctrl = CLKGEN_FIELD(0x10, 0x1, 0), |
b9b8e614 GF |
83 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
84 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL1600_MASK, 0), | |
85 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
86 | .ops = &st_pll1600c65_ops | |
87 | }; | |
88 | ||
dc4febef | 89 | static const struct clkgen_pll_data st_pll800c65_ax = { |
b9b8e614 | 90 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 91 | .pdn_ctrl = CLKGEN_FIELD(0xC, 0x1, 1), |
b9b8e614 GF |
92 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
93 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL800_MASK, 0), | |
94 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
95 | .pdiv = CLKGEN_FIELD(0x0, C65_PDIV_MASK, 16), | |
96 | .ops = &st_pll800c65_ops | |
97 | }; | |
98 | ||
dc4febef | 99 | static const struct clkgen_pll_data st_pll3200c32_a1x_0 = { |
b9b8e614 | 100 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 31), |
fb473862 | 101 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 0), |
b9b8e614 GF |
102 | .locked_status = CLKGEN_FIELD(0x4, 0x1, 31), |
103 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 0x0), | |
104 | .idf = CLKGEN_FIELD(0x4, C32_IDF_MASK, 0x0), | |
105 | .num_odfs = 4, | |
106 | .odf = { CLKGEN_FIELD(0x54, C32_ODF_MASK, 4), | |
107 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 10), | |
108 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 16), | |
109 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 22) }, | |
110 | .odf_gate = { CLKGEN_FIELD(0x54, 0x1, 0), | |
111 | CLKGEN_FIELD(0x54, 0x1, 1), | |
112 | CLKGEN_FIELD(0x54, 0x1, 2), | |
113 | CLKGEN_FIELD(0x54, 0x1, 3) }, | |
114 | .ops = &stm_pll3200c32_ops, | |
115 | }; | |
116 | ||
dc4febef | 117 | static const struct clkgen_pll_data st_pll3200c32_a1x_1 = { |
b9b8e614 | 118 | .pdn_status = CLKGEN_FIELD(0xC, 0x1, 31), |
fb473862 | 119 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 1), |
b9b8e614 GF |
120 | .locked_status = CLKGEN_FIELD(0x10, 0x1, 31), |
121 | .ndiv = CLKGEN_FIELD(0xC, C32_NDIV_MASK, 0x0), | |
122 | .idf = CLKGEN_FIELD(0x10, C32_IDF_MASK, 0x0), | |
123 | .num_odfs = 4, | |
124 | .odf = { CLKGEN_FIELD(0x58, C32_ODF_MASK, 4), | |
125 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 10), | |
126 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 16), | |
127 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 22) }, | |
128 | .odf_gate = { CLKGEN_FIELD(0x58, 0x1, 0), | |
129 | CLKGEN_FIELD(0x58, 0x1, 1), | |
130 | CLKGEN_FIELD(0x58, 0x1, 2), | |
131 | CLKGEN_FIELD(0x58, 0x1, 3) }, | |
132 | .ops = &stm_pll3200c32_ops, | |
133 | }; | |
134 | ||
ec8d27b4 | 135 | /* 415 specific */ |
dc4febef | 136 | static const struct clkgen_pll_data st_pll3200c32_a9_415 = { |
ec8d27b4 | 137 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 138 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
139 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
140 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 9), | |
141 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 22), | |
142 | .num_odfs = 1, | |
143 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 3) }, | |
144 | .odf_gate = { CLKGEN_FIELD(0x0, 0x1, 28) }, | |
145 | .ops = &stm_pll3200c32_ops, | |
146 | }; | |
147 | ||
dc4febef | 148 | static const struct clkgen_pll_data st_pll3200c32_ddr_415 = { |
ec8d27b4 | 149 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 150 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
151 | .locked_status = CLKGEN_FIELD(0x100, 0x1, 0), |
152 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
153 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
154 | .num_odfs = 2, | |
155 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
156 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
157 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
158 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
159 | .ops = &stm_pll3200c32_ops, | |
160 | }; | |
161 | ||
dc4febef | 162 | static const struct clkgen_pll_data st_pll1200c32_gpu_415 = { |
fb473862 GF |
163 | .pdn_status = CLKGEN_FIELD(0x4, 0x1, 0), |
164 | .pdn_ctrl = CLKGEN_FIELD(0x4, 0x1, 0), | |
ec8d27b4 GF |
165 | .locked_status = CLKGEN_FIELD(0x168, 0x1, 0), |
166 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
167 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
168 | .num_odfs = 0, | |
169 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
170 | .ops = &st_pll1200c32_ops, | |
171 | }; | |
172 | ||
173 | /* 416 specific */ | |
dc4febef | 174 | static const struct clkgen_pll_data st_pll3200c32_a9_416 = { |
ec8d27b4 | 175 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 176 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
177 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
178 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
179 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
180 | .num_odfs = 1, | |
181 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8) }, | |
182 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28) }, | |
183 | .ops = &stm_pll3200c32_ops, | |
184 | }; | |
185 | ||
dc4febef | 186 | static const struct clkgen_pll_data st_pll3200c32_ddr_416 = { |
ec8d27b4 | 187 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 188 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
189 | .locked_status = CLKGEN_FIELD(0x10C, 0x1, 0), |
190 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
191 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
192 | .num_odfs = 2, | |
193 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
194 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
195 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
196 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
197 | .ops = &stm_pll3200c32_ops, | |
198 | }; | |
199 | ||
dc4febef | 200 | static const struct clkgen_pll_data st_pll1200c32_gpu_416 = { |
ec8d27b4 | 201 | .pdn_status = CLKGEN_FIELD(0x8E4, 0x1, 3), |
fb473862 | 202 | .pdn_ctrl = CLKGEN_FIELD(0x8E4, 0x1, 3), |
ec8d27b4 GF |
203 | .locked_status = CLKGEN_FIELD(0x90C, 0x1, 0), |
204 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
205 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
206 | .num_odfs = 0, | |
207 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
208 | .ops = &st_pll1200c32_ops, | |
209 | }; | |
210 | ||
eee8f783 GF |
211 | static const struct clkgen_pll_data st_pll3200c32_407_a0 = { |
212 | /* 407 A0 */ | |
213 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 214 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
eee8f783 GF |
215 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
216 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
217 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
218 | .num_odfs = 1, | |
219 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
220 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
221 | .ops = &stm_pll3200c32_ops, | |
222 | }; | |
223 | ||
d34e210e | 224 | static const struct clkgen_pll_data st_pll3200c32_cx_0 = { |
51306d56 GF |
225 | /* 407 C0 PLL0 */ |
226 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 227 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
51306d56 GF |
228 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
229 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
230 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
231 | .num_odfs = 1, | |
232 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
233 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
234 | .ops = &stm_pll3200c32_ops, | |
235 | }; | |
236 | ||
d34e210e | 237 | static const struct clkgen_pll_data st_pll3200c32_cx_1 = { |
51306d56 GF |
238 | /* 407 C0 PLL1 */ |
239 | .pdn_status = CLKGEN_FIELD(0x2c8, 0x1, 8), | |
fb473862 | 240 | .pdn_ctrl = CLKGEN_FIELD(0x2c8, 0x1, 8), |
51306d56 GF |
241 | .locked_status = CLKGEN_FIELD(0x2c8, 0x1, 24), |
242 | .ndiv = CLKGEN_FIELD(0x2cc, C32_NDIV_MASK, 16), | |
243 | .idf = CLKGEN_FIELD(0x2cc, C32_IDF_MASK, 0x0), | |
244 | .num_odfs = 1, | |
245 | .odf = { CLKGEN_FIELD(0x2dc, C32_ODF_MASK, 0) }, | |
246 | .odf_gate = { CLKGEN_FIELD(0x2dc, 0x1, 6) }, | |
247 | .ops = &stm_pll3200c32_ops, | |
248 | }; | |
249 | ||
aaa65d77 GF |
250 | static const struct clkgen_pll_data st_pll3200c32_407_a9 = { |
251 | /* 407 A9 */ | |
252 | .pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0), | |
fb473862 | 253 | .pdn_ctrl = CLKGEN_FIELD(0x1a8, 0x1, 0), |
aaa65d77 GF |
254 | .locked_status = CLKGEN_FIELD(0x87c, 0x1, 0), |
255 | .ndiv = CLKGEN_FIELD(0x1b0, C32_NDIV_MASK, 0), | |
256 | .idf = CLKGEN_FIELD(0x1a8, C32_IDF_MASK, 25), | |
257 | .num_odfs = 1, | |
258 | .odf = { CLKGEN_FIELD(0x1b0, C32_ODF_MASK, 8) }, | |
259 | .odf_gate = { CLKGEN_FIELD(0x1ac, 0x1, 28) }, | |
46a57afd GF |
260 | .switch2pll_en = true, |
261 | .cp = CLKGEN_FIELD(0x1a8, C32_CP_MASK, 1), | |
262 | .switch2pll = CLKGEN_FIELD(0x1a4, 0x1, 1), | |
263 | .lock = &clkgen_a9_lock, | |
264 | .ops = &stm_pll3200c32_a9_ops, | |
aaa65d77 GF |
265 | }; |
266 | ||
0829ea5a GF |
267 | static struct clkgen_pll_data st_pll4600c28_418_a9 = { |
268 | /* 418 A9 */ | |
269 | .pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0), | |
270 | .pdn_ctrl = CLKGEN_FIELD(0x1a8, 0x1, 0), | |
271 | .locked_status = CLKGEN_FIELD(0x87c, 0x1, 0), | |
272 | .ndiv = CLKGEN_FIELD(0x1b0, C28_NDIV_MASK, 0), | |
273 | .idf = CLKGEN_FIELD(0x1a8, C28_IDF_MASK, 25), | |
274 | .num_odfs = 1, | |
275 | .odf = { CLKGEN_FIELD(0x1b0, C28_ODF_MASK, 8) }, | |
276 | .odf_gate = { CLKGEN_FIELD(0x1ac, 0x1, 28) }, | |
277 | .switch2pll_en = true, | |
278 | .switch2pll = CLKGEN_FIELD(0x1a4, 0x1, 1), | |
279 | .lock = &clkgen_a9_lock, | |
280 | .ops = &stm_pll4600c28_ops, | |
281 | }; | |
282 | ||
b9b8e614 GF |
283 | /** |
284 | * DOC: Clock Generated by PLL, rate set and enabled by bootloader | |
285 | * | |
286 | * Traits of this clock: | |
287 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | |
288 | * enable - clk_enable/disable only ensures parent is enabled | |
289 | * rate - rate is fixed. No clk_set_rate support | |
290 | * parent - fixed parent. No clk_set_parent support | |
291 | */ | |
292 | ||
293 | /** | |
294 | * PLL clock that is integrated in the ClockGenA instances on the STiH415 | |
295 | * and STiH416. | |
296 | * | |
297 | * @hw: handle between common and hardware-specific interfaces. | |
298 | * @type: PLL instance type. | |
299 | * @regs_base: base of the PLL configuration register(s). | |
300 | * | |
301 | */ | |
302 | struct clkgen_pll { | |
303 | struct clk_hw hw; | |
304 | struct clkgen_pll_data *data; | |
305 | void __iomem *regs_base; | |
46a57afd GF |
306 | spinlock_t *lock; |
307 | ||
308 | u32 ndiv; | |
309 | u32 idf; | |
310 | u32 odf; | |
311 | u32 cp; | |
b9b8e614 GF |
312 | }; |
313 | ||
314 | #define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw) | |
315 | ||
46a57afd GF |
316 | struct stm_pll { |
317 | unsigned long mdiv; | |
318 | unsigned long ndiv; | |
319 | unsigned long pdiv; | |
320 | unsigned long odf; | |
321 | unsigned long idf; | |
322 | unsigned long ldf; | |
323 | unsigned long cp; | |
324 | }; | |
325 | ||
b9b8e614 GF |
326 | static int clkgen_pll_is_locked(struct clk_hw *hw) |
327 | { | |
328 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
329 | u32 locked = CLKGEN_READ(pll, locked_status); | |
330 | ||
331 | return !!locked; | |
332 | } | |
333 | ||
334 | static int clkgen_pll_is_enabled(struct clk_hw *hw) | |
335 | { | |
336 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
337 | u32 poweroff = CLKGEN_READ(pll, pdn_status); | |
338 | return !poweroff; | |
339 | } | |
340 | ||
46a57afd | 341 | static int __clkgen_pll_enable(struct clk_hw *hw) |
fb473862 GF |
342 | { |
343 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
344 | void __iomem *base = pll->regs_base; | |
345 | struct clkgen_field *field = &pll->data->locked_status; | |
346 | int ret = 0; | |
347 | u32 reg; | |
348 | ||
349 | if (clkgen_pll_is_enabled(hw)) | |
350 | return 0; | |
351 | ||
352 | CLKGEN_WRITE(pll, pdn_ctrl, 0); | |
353 | ||
354 | ret = readl_relaxed_poll_timeout(base + field->offset, reg, | |
355 | !!((reg >> field->shift) & field->mask), 0, 10000); | |
356 | ||
46a57afd GF |
357 | if (!ret) { |
358 | if (pll->data->switch2pll_en) | |
359 | CLKGEN_WRITE(pll, switch2pll, 0); | |
360 | ||
fb473862 | 361 | pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__); |
46a57afd | 362 | } |
fb473862 GF |
363 | |
364 | return ret; | |
365 | } | |
366 | ||
46a57afd GF |
367 | static int clkgen_pll_enable(struct clk_hw *hw) |
368 | { | |
369 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
370 | unsigned long flags = 0; | |
371 | int ret = 0; | |
372 | ||
373 | if (pll->lock) | |
374 | spin_lock_irqsave(pll->lock, flags); | |
375 | ||
376 | ret = __clkgen_pll_enable(hw); | |
377 | ||
378 | if (pll->lock) | |
379 | spin_unlock_irqrestore(pll->lock, flags); | |
380 | ||
381 | return ret; | |
382 | } | |
383 | ||
384 | static void __clkgen_pll_disable(struct clk_hw *hw) | |
fb473862 GF |
385 | { |
386 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
387 | ||
388 | if (!clkgen_pll_is_enabled(hw)) | |
389 | return; | |
390 | ||
46a57afd GF |
391 | if (pll->data->switch2pll_en) |
392 | CLKGEN_WRITE(pll, switch2pll, 1); | |
393 | ||
fb473862 GF |
394 | CLKGEN_WRITE(pll, pdn_ctrl, 1); |
395 | ||
396 | pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__); | |
397 | } | |
398 | ||
46a57afd GF |
399 | static void clkgen_pll_disable(struct clk_hw *hw) |
400 | { | |
401 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
402 | unsigned long flags = 0; | |
403 | ||
404 | if (pll->lock) | |
405 | spin_lock_irqsave(pll->lock, flags); | |
406 | ||
407 | __clkgen_pll_disable(hw); | |
408 | ||
409 | if (pll->lock) | |
410 | spin_unlock_irqrestore(pll->lock, flags); | |
411 | } | |
412 | ||
8e6dd77c | 413 | static unsigned long recalc_stm_pll800c65(struct clk_hw *hw, |
b9b8e614 GF |
414 | unsigned long parent_rate) |
415 | { | |
416 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
417 | unsigned long mdiv, ndiv, pdiv; | |
418 | unsigned long rate; | |
419 | uint64_t res; | |
420 | ||
421 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
422 | return 0; | |
423 | ||
424 | pdiv = CLKGEN_READ(pll, pdiv); | |
425 | mdiv = CLKGEN_READ(pll, mdiv); | |
426 | ndiv = CLKGEN_READ(pll, ndiv); | |
427 | ||
428 | if (!mdiv) | |
429 | mdiv++; /* mdiv=0 or 1 => MDIV=1 */ | |
430 | ||
431 | res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv; | |
432 | rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv)); | |
433 | ||
836ee0f7 | 434 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
435 | |
436 | return rate; | |
437 | ||
438 | } | |
439 | ||
8e6dd77c | 440 | static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw, |
b9b8e614 GF |
441 | unsigned long parent_rate) |
442 | { | |
443 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
444 | unsigned long mdiv, ndiv; | |
445 | unsigned long rate; | |
446 | ||
447 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
448 | return 0; | |
449 | ||
450 | mdiv = CLKGEN_READ(pll, mdiv); | |
451 | ndiv = CLKGEN_READ(pll, ndiv); | |
452 | ||
453 | if (!mdiv) | |
454 | mdiv = 1; | |
455 | ||
456 | /* Note: input is divided by 1000 to avoid overflow */ | |
457 | rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000; | |
458 | ||
836ee0f7 | 459 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
460 | |
461 | return rate; | |
462 | } | |
463 | ||
46a57afd GF |
464 | static int clk_pll3200c32_get_params(unsigned long input, unsigned long output, |
465 | struct stm_pll *pll) | |
466 | { | |
467 | unsigned long i, n; | |
468 | unsigned long deviation = ~0; | |
469 | unsigned long new_freq; | |
470 | long new_deviation; | |
471 | /* Charge pump table: highest ndiv value for cp=6 to 25 */ | |
472 | static const unsigned char cp_table[] = { | |
473 | 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, | |
474 | 128, 136, 144, 152, 160, 168, 176, 184, 192 | |
475 | }; | |
476 | ||
477 | /* Output clock range: 800Mhz to 1600Mhz */ | |
478 | if (output < 800000000 || output > 1600000000) | |
479 | return -EINVAL; | |
480 | ||
481 | input /= 1000; | |
482 | output /= 1000; | |
483 | ||
484 | for (i = 1; i <= 7 && deviation; i++) { | |
485 | n = i * output / (2 * input); | |
486 | ||
487 | /* Checks */ | |
488 | if (n < 8) | |
489 | continue; | |
490 | if (n > 200) | |
491 | break; | |
492 | ||
493 | new_freq = (input * 2 * n) / i; | |
494 | ||
495 | new_deviation = abs(new_freq - output); | |
496 | ||
497 | if (!new_deviation || new_deviation < deviation) { | |
498 | pll->idf = i; | |
499 | pll->ndiv = n; | |
500 | deviation = new_deviation; | |
501 | } | |
502 | } | |
503 | ||
504 | if (deviation == ~0) /* No solution found */ | |
505 | return -EINVAL; | |
506 | ||
507 | /* Computing recommended charge pump value */ | |
508 | for (pll->cp = 6; pll->ndiv > cp_table[pll->cp-6]; (pll->cp)++) | |
509 | ; | |
510 | ||
511 | return 0; | |
512 | } | |
513 | ||
514 | static int clk_pll3200c32_get_rate(unsigned long input, struct stm_pll *pll, | |
515 | unsigned long *rate) | |
516 | { | |
517 | if (!pll->idf) | |
518 | pll->idf = 1; | |
519 | ||
520 | *rate = ((2 * (input / 1000) * pll->ndiv) / pll->idf) * 1000; | |
521 | ||
522 | return 0; | |
523 | } | |
524 | ||
8e6dd77c | 525 | static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw, |
b9b8e614 GF |
526 | unsigned long parent_rate) |
527 | { | |
528 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
529 | unsigned long ndiv, idf; | |
530 | unsigned long rate = 0; | |
531 | ||
532 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
533 | return 0; | |
534 | ||
535 | ndiv = CLKGEN_READ(pll, ndiv); | |
536 | idf = CLKGEN_READ(pll, idf); | |
537 | ||
538 | if (idf) | |
539 | /* Note: input is divided to avoid overflow */ | |
540 | rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000; | |
541 | ||
836ee0f7 | 542 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
543 | |
544 | return rate; | |
545 | } | |
546 | ||
46a57afd GF |
547 | static long round_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, |
548 | unsigned long *prate) | |
549 | { | |
550 | struct stm_pll params; | |
551 | ||
552 | if (!clk_pll3200c32_get_params(*prate, rate, ¶ms)) | |
553 | clk_pll3200c32_get_rate(*prate, ¶ms, &rate); | |
554 | else { | |
555 | pr_debug("%s: %s rate %ld Invalid\n", __func__, | |
556 | __clk_get_name(hw->clk), rate); | |
557 | return 0; | |
558 | } | |
559 | ||
560 | pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n", | |
561 | __func__, __clk_get_name(hw->clk), | |
562 | rate, (unsigned int)params.ndiv, | |
563 | (unsigned int)params.idf); | |
564 | ||
565 | return rate; | |
566 | } | |
567 | ||
568 | static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, | |
569 | unsigned long parent_rate) | |
570 | { | |
571 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
572 | struct stm_pll params; | |
573 | long hwrate = 0; | |
574 | unsigned long flags = 0; | |
575 | ||
576 | if (!rate || !parent_rate) | |
577 | return -EINVAL; | |
578 | ||
579 | if (!clk_pll3200c32_get_params(parent_rate, rate, ¶ms)) | |
580 | clk_pll3200c32_get_rate(parent_rate, ¶ms, &hwrate); | |
581 | ||
582 | pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n", | |
583 | __func__, __clk_get_name(hw->clk), | |
584 | hwrate, (unsigned int)params.ndiv, | |
585 | (unsigned int)params.idf); | |
586 | ||
587 | if (!hwrate) | |
588 | return -EINVAL; | |
589 | ||
590 | pll->ndiv = params.ndiv; | |
591 | pll->idf = params.idf; | |
592 | pll->cp = params.cp; | |
593 | ||
594 | __clkgen_pll_disable(hw); | |
595 | ||
596 | if (pll->lock) | |
597 | spin_lock_irqsave(pll->lock, flags); | |
598 | ||
599 | CLKGEN_WRITE(pll, ndiv, pll->ndiv); | |
600 | CLKGEN_WRITE(pll, idf, pll->idf); | |
601 | CLKGEN_WRITE(pll, cp, pll->cp); | |
602 | ||
603 | if (pll->lock) | |
604 | spin_unlock_irqrestore(pll->lock, flags); | |
605 | ||
606 | __clkgen_pll_enable(hw); | |
607 | ||
608 | return 0; | |
609 | } | |
610 | ||
8e6dd77c | 611 | static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw, |
b9b8e614 GF |
612 | unsigned long parent_rate) |
613 | { | |
614 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
615 | unsigned long odf, ldf, idf; | |
616 | unsigned long rate; | |
617 | ||
618 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
619 | return 0; | |
620 | ||
621 | odf = CLKGEN_READ(pll, odf[0]); | |
622 | ldf = CLKGEN_READ(pll, ldf); | |
623 | idf = CLKGEN_READ(pll, idf); | |
624 | ||
625 | if (!idf) /* idf==0 means 1 */ | |
626 | idf = 1; | |
627 | if (!odf) /* odf==0 means 1 */ | |
628 | odf = 1; | |
629 | ||
630 | /* Note: input is divided by 1000 to avoid overflow */ | |
631 | rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000; | |
632 | ||
836ee0f7 | 633 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
634 | |
635 | return rate; | |
636 | } | |
637 | ||
0829ea5a GF |
638 | /* PLL output structure |
639 | * FVCO >> /2 >> FVCOBY2 (no output) | |
640 | * |> Divider (ODF) >> PHI | |
641 | * | |
642 | * FVCOby2 output = (input * 2 * NDIV) / IDF (assuming FRAC_CONTROL==L) | |
643 | * | |
644 | * Rules: | |
645 | * 4Mhz <= INFF input <= 350Mhz | |
646 | * 4Mhz <= INFIN (INFF / IDF) <= 50Mhz | |
647 | * 19.05Mhz <= FVCOby2 output (PHI w ODF=1) <= 3000Mhz | |
648 | * 1 <= i (register/dec value for IDF) <= 7 | |
649 | * 8 <= n (register/dec value for NDIV) <= 246 | |
650 | */ | |
651 | ||
652 | static int clk_pll4600c28_get_params(unsigned long input, unsigned long output, | |
653 | struct stm_pll *pll) | |
654 | { | |
655 | ||
656 | unsigned long i, infin, n; | |
657 | unsigned long deviation = ~0; | |
658 | unsigned long new_freq, new_deviation; | |
659 | ||
660 | /* Output clock range: 19Mhz to 3000Mhz */ | |
661 | if (output < 19000000 || output > 3000000000u) | |
662 | return -EINVAL; | |
663 | ||
664 | /* For better jitter, IDF should be smallest and NDIV must be maximum */ | |
665 | for (i = 1; i <= 7 && deviation; i++) { | |
666 | /* INFIN checks */ | |
667 | infin = input / i; | |
668 | if (infin < 4000000 || infin > 50000000) | |
669 | continue; /* Invalid case */ | |
670 | ||
671 | n = output / (infin * 2); | |
672 | if (n < 8 || n > 246) | |
673 | continue; /* Invalid case */ | |
674 | if (n < 246) | |
675 | n++; /* To work around 'y' when n=x.y */ | |
676 | ||
677 | for (; n >= 8 && deviation; n--) { | |
678 | new_freq = infin * 2 * n; | |
679 | if (new_freq < output) | |
680 | break; /* Optimization: shorting loop */ | |
681 | ||
682 | new_deviation = new_freq - output; | |
683 | if (!new_deviation || new_deviation < deviation) { | |
684 | pll->idf = i; | |
685 | pll->ndiv = n; | |
686 | deviation = new_deviation; | |
687 | } | |
688 | } | |
689 | } | |
690 | ||
691 | if (deviation == ~0) /* No solution found */ | |
692 | return -EINVAL; | |
693 | ||
694 | return 0; | |
695 | } | |
696 | ||
697 | static int clk_pll4600c28_get_rate(unsigned long input, struct stm_pll *pll, | |
698 | unsigned long *rate) | |
699 | { | |
700 | if (!pll->idf) | |
701 | pll->idf = 1; | |
702 | ||
703 | *rate = (input / pll->idf) * 2 * pll->ndiv; | |
704 | ||
705 | return 0; | |
706 | } | |
707 | ||
708 | static unsigned long recalc_stm_pll4600c28(struct clk_hw *hw, | |
709 | unsigned long parent_rate) | |
710 | { | |
711 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
712 | struct stm_pll params; | |
713 | unsigned long rate; | |
714 | ||
715 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
716 | return 0; | |
717 | ||
718 | params.ndiv = CLKGEN_READ(pll, ndiv); | |
719 | params.idf = CLKGEN_READ(pll, idf); | |
720 | ||
721 | clk_pll4600c28_get_rate(parent_rate, ¶ms, &rate); | |
722 | ||
723 | pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate); | |
724 | ||
725 | return rate; | |
726 | } | |
727 | ||
728 | static long round_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, | |
729 | unsigned long *prate) | |
730 | { | |
731 | struct stm_pll params; | |
732 | ||
733 | if (!clk_pll4600c28_get_params(*prate, rate, ¶ms)) { | |
734 | clk_pll4600c28_get_rate(*prate, ¶ms, &rate); | |
735 | } else { | |
736 | pr_debug("%s: %s rate %ld Invalid\n", __func__, | |
737 | __clk_get_name(hw->clk), rate); | |
738 | return 0; | |
739 | } | |
740 | ||
741 | pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n", | |
742 | __func__, __clk_get_name(hw->clk), | |
743 | rate, (unsigned int)params.ndiv, | |
744 | (unsigned int)params.idf); | |
745 | ||
746 | return rate; | |
747 | } | |
748 | ||
749 | static int set_rate_stm_pll4600c28(struct clk_hw *hw, unsigned long rate, | |
750 | unsigned long parent_rate) | |
751 | { | |
752 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
753 | struct stm_pll params; | |
754 | long hwrate; | |
755 | unsigned long flags = 0; | |
756 | ||
757 | if (!rate || !parent_rate) | |
758 | return -EINVAL; | |
759 | ||
760 | if (!clk_pll4600c28_get_params(parent_rate, rate, ¶ms)) { | |
761 | clk_pll4600c28_get_rate(parent_rate, ¶ms, &hwrate); | |
762 | } else { | |
763 | pr_debug("%s: %s rate %ld Invalid\n", __func__, | |
764 | __clk_get_name(hw->clk), rate); | |
765 | return -EINVAL; | |
766 | } | |
767 | ||
768 | pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n", | |
769 | __func__, __clk_get_name(hw->clk), | |
770 | hwrate, (unsigned int)params.ndiv, | |
771 | (unsigned int)params.idf); | |
772 | ||
773 | if (!hwrate) | |
774 | return -EINVAL; | |
775 | ||
776 | pll->ndiv = params.ndiv; | |
777 | pll->idf = params.idf; | |
778 | ||
779 | __clkgen_pll_disable(hw); | |
780 | ||
781 | if (pll->lock) | |
782 | spin_lock_irqsave(pll->lock, flags); | |
783 | ||
784 | CLKGEN_WRITE(pll, ndiv, pll->ndiv); | |
785 | CLKGEN_WRITE(pll, idf, pll->idf); | |
786 | ||
787 | if (pll->lock) | |
788 | spin_unlock_irqrestore(pll->lock, flags); | |
789 | ||
790 | __clkgen_pll_enable(hw); | |
791 | ||
792 | return 0; | |
793 | } | |
794 | ||
b9b8e614 | 795 | static const struct clk_ops st_pll1600c65_ops = { |
fb473862 GF |
796 | .enable = clkgen_pll_enable, |
797 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
798 | .is_enabled = clkgen_pll_is_enabled, |
799 | .recalc_rate = recalc_stm_pll1600c65, | |
800 | }; | |
801 | ||
802 | static const struct clk_ops st_pll800c65_ops = { | |
fb473862 GF |
803 | .enable = clkgen_pll_enable, |
804 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
805 | .is_enabled = clkgen_pll_is_enabled, |
806 | .recalc_rate = recalc_stm_pll800c65, | |
807 | }; | |
808 | ||
809 | static const struct clk_ops stm_pll3200c32_ops = { | |
fb473862 GF |
810 | .enable = clkgen_pll_enable, |
811 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
812 | .is_enabled = clkgen_pll_is_enabled, |
813 | .recalc_rate = recalc_stm_pll3200c32, | |
814 | }; | |
815 | ||
46a57afd GF |
816 | static const struct clk_ops stm_pll3200c32_a9_ops = { |
817 | .enable = clkgen_pll_enable, | |
818 | .disable = clkgen_pll_disable, | |
819 | .is_enabled = clkgen_pll_is_enabled, | |
820 | .recalc_rate = recalc_stm_pll3200c32, | |
821 | .round_rate = round_rate_stm_pll3200c32, | |
822 | .set_rate = set_rate_stm_pll3200c32, | |
823 | }; | |
824 | ||
b9b8e614 | 825 | static const struct clk_ops st_pll1200c32_ops = { |
fb473862 GF |
826 | .enable = clkgen_pll_enable, |
827 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
828 | .is_enabled = clkgen_pll_is_enabled, |
829 | .recalc_rate = recalc_stm_pll1200c32, | |
830 | }; | |
831 | ||
0829ea5a GF |
832 | static const struct clk_ops stm_pll4600c28_ops = { |
833 | .enable = clkgen_pll_enable, | |
834 | .disable = clkgen_pll_disable, | |
835 | .is_enabled = clkgen_pll_is_enabled, | |
836 | .recalc_rate = recalc_stm_pll4600c28, | |
837 | .round_rate = round_rate_stm_pll4600c28, | |
838 | .set_rate = set_rate_stm_pll4600c28, | |
839 | }; | |
840 | ||
b9b8e614 GF |
841 | static struct clk * __init clkgen_pll_register(const char *parent_name, |
842 | struct clkgen_pll_data *pll_data, | |
6ca59e6e | 843 | void __iomem *reg, unsigned long pll_flags, |
46a57afd | 844 | const char *clk_name, spinlock_t *lock) |
b9b8e614 GF |
845 | { |
846 | struct clkgen_pll *pll; | |
847 | struct clk *clk; | |
848 | struct clk_init_data init; | |
849 | ||
850 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | |
851 | if (!pll) | |
852 | return ERR_PTR(-ENOMEM); | |
853 | ||
854 | init.name = clk_name; | |
855 | init.ops = pll_data->ops; | |
856 | ||
6ca59e6e | 857 | init.flags = pll_flags | CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; |
b9b8e614 GF |
858 | init.parent_names = &parent_name; |
859 | init.num_parents = 1; | |
860 | ||
861 | pll->data = pll_data; | |
862 | pll->regs_base = reg; | |
863 | pll->hw.init = &init; | |
46a57afd | 864 | pll->lock = lock; |
b9b8e614 GF |
865 | |
866 | clk = clk_register(NULL, &pll->hw); | |
867 | if (IS_ERR(clk)) { | |
868 | kfree(pll); | |
869 | return clk; | |
870 | } | |
871 | ||
872 | pr_debug("%s: parent %s rate %lu\n", | |
873 | __clk_get_name(clk), | |
874 | __clk_get_name(clk_get_parent(clk)), | |
875 | clk_get_rate(clk)); | |
876 | ||
877 | return clk; | |
878 | } | |
879 | ||
880 | static struct clk * __init clkgen_c65_lsdiv_register(const char *parent_name, | |
881 | const char *clk_name) | |
882 | { | |
883 | struct clk *clk; | |
884 | ||
885 | clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, 1, 2); | |
886 | if (IS_ERR(clk)) | |
887 | return clk; | |
888 | ||
889 | pr_debug("%s: parent %s rate %lu\n", | |
890 | __clk_get_name(clk), | |
891 | __clk_get_name(clk_get_parent(clk)), | |
892 | clk_get_rate(clk)); | |
893 | return clk; | |
894 | } | |
895 | ||
896 | static void __iomem * __init clkgen_get_register_base( | |
897 | struct device_node *np) | |
898 | { | |
899 | struct device_node *pnode; | |
900 | void __iomem *reg = NULL; | |
901 | ||
902 | pnode = of_get_parent(np); | |
903 | if (!pnode) | |
904 | return NULL; | |
905 | ||
906 | reg = of_iomap(pnode, 0); | |
907 | ||
908 | of_node_put(pnode); | |
909 | return reg; | |
910 | } | |
911 | ||
912 | #define CLKGENAx_PLL0_OFFSET 0x0 | |
913 | #define CLKGENAx_PLL1_OFFSET 0x4 | |
914 | ||
915 | static void __init clkgena_c65_pll_setup(struct device_node *np) | |
916 | { | |
917 | const int num_pll_outputs = 3; | |
918 | struct clk_onecell_data *clk_data; | |
919 | const char *parent_name; | |
920 | void __iomem *reg; | |
921 | const char *clk_name; | |
922 | ||
923 | parent_name = of_clk_get_parent_name(np, 0); | |
924 | if (!parent_name) | |
925 | return; | |
926 | ||
927 | reg = clkgen_get_register_base(np); | |
928 | if (!reg) | |
929 | return; | |
930 | ||
931 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
932 | if (!clk_data) | |
933 | return; | |
934 | ||
935 | clk_data->clk_num = num_pll_outputs; | |
936 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
937 | GFP_KERNEL); | |
938 | ||
939 | if (!clk_data->clks) | |
940 | goto err; | |
941 | ||
942 | if (of_property_read_string_index(np, "clock-output-names", | |
943 | 0, &clk_name)) | |
944 | goto err; | |
945 | ||
946 | /* | |
947 | * PLL0 HS (high speed) output | |
948 | */ | |
949 | clk_data->clks[0] = clkgen_pll_register(parent_name, | |
dc4febef | 950 | (struct clkgen_pll_data *) &st_pll1600c65_ax, |
6ca59e6e | 951 | reg + CLKGENAx_PLL0_OFFSET, 0, clk_name, NULL); |
b9b8e614 GF |
952 | |
953 | if (IS_ERR(clk_data->clks[0])) | |
954 | goto err; | |
955 | ||
956 | if (of_property_read_string_index(np, "clock-output-names", | |
957 | 1, &clk_name)) | |
958 | goto err; | |
959 | ||
960 | /* | |
961 | * PLL0 LS (low speed) output, which is a fixed divide by 2 of the | |
962 | * high speed output. | |
963 | */ | |
964 | clk_data->clks[1] = clkgen_c65_lsdiv_register(__clk_get_name | |
965 | (clk_data->clks[0]), | |
966 | clk_name); | |
967 | ||
968 | if (IS_ERR(clk_data->clks[1])) | |
969 | goto err; | |
970 | ||
971 | if (of_property_read_string_index(np, "clock-output-names", | |
972 | 2, &clk_name)) | |
973 | goto err; | |
974 | ||
975 | /* | |
976 | * PLL1 output | |
977 | */ | |
978 | clk_data->clks[2] = clkgen_pll_register(parent_name, | |
dc4febef | 979 | (struct clkgen_pll_data *) &st_pll800c65_ax, |
6ca59e6e | 980 | reg + CLKGENAx_PLL1_OFFSET, 0, clk_name, NULL); |
b9b8e614 GF |
981 | |
982 | if (IS_ERR(clk_data->clks[2])) | |
983 | goto err; | |
984 | ||
985 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
986 | return; | |
987 | ||
988 | err: | |
989 | kfree(clk_data->clks); | |
990 | kfree(clk_data); | |
991 | } | |
992 | CLK_OF_DECLARE(clkgena_c65_plls, | |
993 | "st,clkgena-plls-c65", clkgena_c65_pll_setup); | |
994 | ||
995 | static struct clk * __init clkgen_odf_register(const char *parent_name, | |
8e6dd77c | 996 | void __iomem *reg, |
b9b8e614 | 997 | struct clkgen_pll_data *pll_data, |
6ca59e6e | 998 | unsigned long pll_flags, int odf, |
b9b8e614 GF |
999 | spinlock_t *odf_lock, |
1000 | const char *odf_name) | |
1001 | { | |
1002 | struct clk *clk; | |
1003 | unsigned long flags; | |
1004 | struct clk_gate *gate; | |
1005 | struct clk_divider *div; | |
1006 | ||
6ca59e6e | 1007 | flags = pll_flags | CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT; |
b9b8e614 GF |
1008 | |
1009 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | |
1010 | if (!gate) | |
1011 | return ERR_PTR(-ENOMEM); | |
1012 | ||
1013 | gate->flags = CLK_GATE_SET_TO_DISABLE; | |
1014 | gate->reg = reg + pll_data->odf_gate[odf].offset; | |
1015 | gate->bit_idx = pll_data->odf_gate[odf].shift; | |
1016 | gate->lock = odf_lock; | |
1017 | ||
1018 | div = kzalloc(sizeof(*div), GFP_KERNEL); | |
72b1c2c3 VI |
1019 | if (!div) { |
1020 | kfree(gate); | |
b9b8e614 | 1021 | return ERR_PTR(-ENOMEM); |
72b1c2c3 | 1022 | } |
b9b8e614 GF |
1023 | |
1024 | div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; | |
1025 | div->reg = reg + pll_data->odf[odf].offset; | |
1026 | div->shift = pll_data->odf[odf].shift; | |
1027 | div->width = fls(pll_data->odf[odf].mask); | |
1028 | div->lock = odf_lock; | |
1029 | ||
1030 | clk = clk_register_composite(NULL, odf_name, &parent_name, 1, | |
1031 | NULL, NULL, | |
1032 | &div->hw, &clk_divider_ops, | |
1033 | &gate->hw, &clk_gate_ops, | |
1034 | flags); | |
1035 | if (IS_ERR(clk)) | |
1036 | return clk; | |
1037 | ||
1038 | pr_debug("%s: parent %s rate %lu\n", | |
1039 | __clk_get_name(clk), | |
1040 | __clk_get_name(clk_get_parent(clk)), | |
1041 | clk_get_rate(clk)); | |
1042 | return clk; | |
1043 | } | |
1044 | ||
f375573c | 1045 | static const struct of_device_id c32_pll_of_match[] = { |
b9b8e614 GF |
1046 | { |
1047 | .compatible = "st,plls-c32-a1x-0", | |
1048 | .data = &st_pll3200c32_a1x_0, | |
1049 | }, | |
1050 | { | |
1051 | .compatible = "st,plls-c32-a1x-1", | |
1052 | .data = &st_pll3200c32_a1x_1, | |
1053 | }, | |
ec8d27b4 GF |
1054 | { |
1055 | .compatible = "st,stih415-plls-c32-a9", | |
1056 | .data = &st_pll3200c32_a9_415, | |
1057 | }, | |
1058 | { | |
1059 | .compatible = "st,stih415-plls-c32-ddr", | |
1060 | .data = &st_pll3200c32_ddr_415, | |
1061 | }, | |
1062 | { | |
1063 | .compatible = "st,stih416-plls-c32-a9", | |
1064 | .data = &st_pll3200c32_a9_416, | |
1065 | }, | |
1066 | { | |
1067 | .compatible = "st,stih416-plls-c32-ddr", | |
1068 | .data = &st_pll3200c32_ddr_416, | |
1069 | }, | |
eee8f783 GF |
1070 | { |
1071 | .compatible = "st,stih407-plls-c32-a0", | |
1072 | .data = &st_pll3200c32_407_a0, | |
1073 | }, | |
51306d56 | 1074 | { |
d34e210e GF |
1075 | .compatible = "st,plls-c32-cx_0", |
1076 | .data = &st_pll3200c32_cx_0, | |
51306d56 GF |
1077 | }, |
1078 | { | |
d34e210e GF |
1079 | .compatible = "st,plls-c32-cx_1", |
1080 | .data = &st_pll3200c32_cx_1, | |
51306d56 | 1081 | }, |
aaa65d77 GF |
1082 | { |
1083 | .compatible = "st,stih407-plls-c32-a9", | |
1084 | .data = &st_pll3200c32_407_a9, | |
1085 | }, | |
0829ea5a GF |
1086 | { |
1087 | .compatible = "st,stih418-plls-c28-a9", | |
1088 | .data = &st_pll4600c28_418_a9, | |
1089 | }, | |
b9b8e614 GF |
1090 | {} |
1091 | }; | |
1092 | ||
1093 | static void __init clkgen_c32_pll_setup(struct device_node *np) | |
1094 | { | |
1095 | const struct of_device_id *match; | |
1096 | struct clk *clk; | |
1097 | const char *parent_name, *pll_name; | |
1098 | void __iomem *pll_base; | |
1099 | int num_odfs, odf; | |
1100 | struct clk_onecell_data *clk_data; | |
1101 | struct clkgen_pll_data *data; | |
6ca59e6e | 1102 | unsigned long pll_flags = 0; |
b9b8e614 GF |
1103 | |
1104 | match = of_match_node(c32_pll_of_match, np); | |
1105 | if (!match) { | |
1106 | pr_err("%s: No matching data\n", __func__); | |
1107 | return; | |
1108 | } | |
1109 | ||
1110 | data = (struct clkgen_pll_data *) match->data; | |
1111 | ||
1112 | parent_name = of_clk_get_parent_name(np, 0); | |
1113 | if (!parent_name) | |
1114 | return; | |
1115 | ||
1116 | pll_base = clkgen_get_register_base(np); | |
1117 | if (!pll_base) | |
1118 | return; | |
1119 | ||
6ca59e6e LJ |
1120 | of_clk_detect_critical(np, 0, &pll_flags); |
1121 | ||
1122 | clk = clkgen_pll_register(parent_name, data, pll_base, pll_flags, | |
1123 | np->name, data->lock); | |
b9b8e614 GF |
1124 | if (IS_ERR(clk)) |
1125 | return; | |
1126 | ||
1127 | pll_name = __clk_get_name(clk); | |
1128 | ||
1129 | num_odfs = data->num_odfs; | |
1130 | ||
1131 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
1132 | if (!clk_data) | |
1133 | return; | |
1134 | ||
1135 | clk_data->clk_num = num_odfs; | |
1136 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
1137 | GFP_KERNEL); | |
1138 | ||
1139 | if (!clk_data->clks) | |
1140 | goto err; | |
1141 | ||
1142 | for (odf = 0; odf < num_odfs; odf++) { | |
1143 | struct clk *clk; | |
1144 | const char *clk_name; | |
6ca59e6e | 1145 | unsigned long odf_flags = 0; |
b9b8e614 GF |
1146 | |
1147 | if (of_property_read_string_index(np, "clock-output-names", | |
1148 | odf, &clk_name)) | |
1149 | return; | |
1150 | ||
6ca59e6e LJ |
1151 | of_clk_detect_critical(np, odf, &odf_flags); |
1152 | ||
1153 | clk = clkgen_odf_register(pll_name, pll_base, data, odf_flags, | |
b9b8e614 GF |
1154 | odf, &clkgena_c32_odf_lock, clk_name); |
1155 | if (IS_ERR(clk)) | |
1156 | goto err; | |
1157 | ||
1158 | clk_data->clks[odf] = clk; | |
1159 | } | |
1160 | ||
1161 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
1162 | return; | |
1163 | ||
1164 | err: | |
1165 | kfree(pll_name); | |
1166 | kfree(clk_data->clks); | |
1167 | kfree(clk_data); | |
1168 | } | |
1169 | CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup); | |
ec8d27b4 | 1170 | |
f375573c | 1171 | static const struct of_device_id c32_gpu_pll_of_match[] = { |
ec8d27b4 GF |
1172 | { |
1173 | .compatible = "st,stih415-gpu-pll-c32", | |
1174 | .data = &st_pll1200c32_gpu_415, | |
1175 | }, | |
1176 | { | |
1177 | .compatible = "st,stih416-gpu-pll-c32", | |
1178 | .data = &st_pll1200c32_gpu_416, | |
1179 | }, | |
70040b35 | 1180 | {} |
ec8d27b4 GF |
1181 | }; |
1182 | ||
1183 | static void __init clkgengpu_c32_pll_setup(struct device_node *np) | |
1184 | { | |
1185 | const struct of_device_id *match; | |
1186 | struct clk *clk; | |
1187 | const char *parent_name; | |
1188 | void __iomem *reg; | |
1189 | const char *clk_name; | |
1190 | struct clkgen_pll_data *data; | |
1191 | ||
1192 | match = of_match_node(c32_gpu_pll_of_match, np); | |
1193 | if (!match) { | |
1194 | pr_err("%s: No matching data\n", __func__); | |
1195 | return; | |
1196 | } | |
1197 | ||
1198 | data = (struct clkgen_pll_data *)match->data; | |
1199 | ||
1200 | parent_name = of_clk_get_parent_name(np, 0); | |
1201 | if (!parent_name) | |
1202 | return; | |
1203 | ||
1204 | reg = clkgen_get_register_base(np); | |
1205 | if (!reg) | |
1206 | return; | |
1207 | ||
1208 | if (of_property_read_string_index(np, "clock-output-names", | |
1209 | 0, &clk_name)) | |
1210 | return; | |
1211 | ||
1212 | /* | |
1213 | * PLL 1200MHz output | |
1214 | */ | |
6ca59e6e LJ |
1215 | clk = clkgen_pll_register(parent_name, data, reg, |
1216 | 0, clk_name, data->lock); | |
ec8d27b4 GF |
1217 | |
1218 | if (!IS_ERR(clk)) | |
1219 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | |
1220 | ||
1221 | return; | |
1222 | } | |
1223 | CLK_OF_DECLARE(clkgengpu_c32_pll, | |
1224 | "st,clkgengpu-pll-c32", clkgengpu_c32_pll_setup); |