]>
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 | ||
47 | struct clkgen_pll_data { | |
48 | struct clkgen_field pdn_status; | |
fb473862 | 49 | struct clkgen_field pdn_ctrl; |
b9b8e614 GF |
50 | struct clkgen_field locked_status; |
51 | struct clkgen_field mdiv; | |
52 | struct clkgen_field ndiv; | |
53 | struct clkgen_field pdiv; | |
54 | struct clkgen_field idf; | |
55 | struct clkgen_field ldf; | |
46a57afd | 56 | struct clkgen_field cp; |
b9b8e614 GF |
57 | unsigned int num_odfs; |
58 | struct clkgen_field odf[C32_MAX_ODFS]; | |
59 | struct clkgen_field odf_gate[C32_MAX_ODFS]; | |
46a57afd GF |
60 | bool switch2pll_en; |
61 | struct clkgen_field switch2pll; | |
62 | spinlock_t *lock; | |
b9b8e614 GF |
63 | const struct clk_ops *ops; |
64 | }; | |
65 | ||
66 | static const struct clk_ops st_pll1600c65_ops; | |
67 | static const struct clk_ops st_pll800c65_ops; | |
68 | static const struct clk_ops stm_pll3200c32_ops; | |
46a57afd | 69 | static const struct clk_ops stm_pll3200c32_a9_ops; |
b9b8e614 GF |
70 | static const struct clk_ops st_pll1200c32_ops; |
71 | ||
dc4febef | 72 | static const struct clkgen_pll_data st_pll1600c65_ax = { |
b9b8e614 | 73 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 74 | .pdn_ctrl = CLKGEN_FIELD(0x10, 0x1, 0), |
b9b8e614 GF |
75 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
76 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL1600_MASK, 0), | |
77 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
78 | .ops = &st_pll1600c65_ops | |
79 | }; | |
80 | ||
dc4febef | 81 | static const struct clkgen_pll_data st_pll800c65_ax = { |
b9b8e614 | 82 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 83 | .pdn_ctrl = CLKGEN_FIELD(0xC, 0x1, 1), |
b9b8e614 GF |
84 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
85 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL800_MASK, 0), | |
86 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
87 | .pdiv = CLKGEN_FIELD(0x0, C65_PDIV_MASK, 16), | |
88 | .ops = &st_pll800c65_ops | |
89 | }; | |
90 | ||
dc4febef | 91 | static const struct clkgen_pll_data st_pll3200c32_a1x_0 = { |
b9b8e614 | 92 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 31), |
fb473862 | 93 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 0), |
b9b8e614 GF |
94 | .locked_status = CLKGEN_FIELD(0x4, 0x1, 31), |
95 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 0x0), | |
96 | .idf = CLKGEN_FIELD(0x4, C32_IDF_MASK, 0x0), | |
97 | .num_odfs = 4, | |
98 | .odf = { CLKGEN_FIELD(0x54, C32_ODF_MASK, 4), | |
99 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 10), | |
100 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 16), | |
101 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 22) }, | |
102 | .odf_gate = { CLKGEN_FIELD(0x54, 0x1, 0), | |
103 | CLKGEN_FIELD(0x54, 0x1, 1), | |
104 | CLKGEN_FIELD(0x54, 0x1, 2), | |
105 | CLKGEN_FIELD(0x54, 0x1, 3) }, | |
106 | .ops = &stm_pll3200c32_ops, | |
107 | }; | |
108 | ||
dc4febef | 109 | static const struct clkgen_pll_data st_pll3200c32_a1x_1 = { |
b9b8e614 | 110 | .pdn_status = CLKGEN_FIELD(0xC, 0x1, 31), |
fb473862 | 111 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 1), |
b9b8e614 GF |
112 | .locked_status = CLKGEN_FIELD(0x10, 0x1, 31), |
113 | .ndiv = CLKGEN_FIELD(0xC, C32_NDIV_MASK, 0x0), | |
114 | .idf = CLKGEN_FIELD(0x10, C32_IDF_MASK, 0x0), | |
115 | .num_odfs = 4, | |
116 | .odf = { CLKGEN_FIELD(0x58, C32_ODF_MASK, 4), | |
117 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 10), | |
118 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 16), | |
119 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 22) }, | |
120 | .odf_gate = { CLKGEN_FIELD(0x58, 0x1, 0), | |
121 | CLKGEN_FIELD(0x58, 0x1, 1), | |
122 | CLKGEN_FIELD(0x58, 0x1, 2), | |
123 | CLKGEN_FIELD(0x58, 0x1, 3) }, | |
124 | .ops = &stm_pll3200c32_ops, | |
125 | }; | |
126 | ||
ec8d27b4 | 127 | /* 415 specific */ |
dc4febef | 128 | static const struct clkgen_pll_data st_pll3200c32_a9_415 = { |
ec8d27b4 | 129 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 130 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
131 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
132 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 9), | |
133 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 22), | |
134 | .num_odfs = 1, | |
135 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 3) }, | |
136 | .odf_gate = { CLKGEN_FIELD(0x0, 0x1, 28) }, | |
137 | .ops = &stm_pll3200c32_ops, | |
138 | }; | |
139 | ||
dc4febef | 140 | static const struct clkgen_pll_data st_pll3200c32_ddr_415 = { |
ec8d27b4 | 141 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 142 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
143 | .locked_status = CLKGEN_FIELD(0x100, 0x1, 0), |
144 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
145 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
146 | .num_odfs = 2, | |
147 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
148 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
149 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
150 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
151 | .ops = &stm_pll3200c32_ops, | |
152 | }; | |
153 | ||
dc4febef | 154 | static const struct clkgen_pll_data st_pll1200c32_gpu_415 = { |
fb473862 GF |
155 | .pdn_status = CLKGEN_FIELD(0x4, 0x1, 0), |
156 | .pdn_ctrl = CLKGEN_FIELD(0x4, 0x1, 0), | |
ec8d27b4 GF |
157 | .locked_status = CLKGEN_FIELD(0x168, 0x1, 0), |
158 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
159 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
160 | .num_odfs = 0, | |
161 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
162 | .ops = &st_pll1200c32_ops, | |
163 | }; | |
164 | ||
165 | /* 416 specific */ | |
dc4febef | 166 | static const struct clkgen_pll_data st_pll3200c32_a9_416 = { |
ec8d27b4 | 167 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 168 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
169 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
170 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
171 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
172 | .num_odfs = 1, | |
173 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8) }, | |
174 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28) }, | |
175 | .ops = &stm_pll3200c32_ops, | |
176 | }; | |
177 | ||
dc4febef | 178 | static const struct clkgen_pll_data st_pll3200c32_ddr_416 = { |
ec8d27b4 | 179 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 180 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
181 | .locked_status = CLKGEN_FIELD(0x10C, 0x1, 0), |
182 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
183 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
184 | .num_odfs = 2, | |
185 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
186 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
187 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
188 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
189 | .ops = &stm_pll3200c32_ops, | |
190 | }; | |
191 | ||
dc4febef | 192 | static const struct clkgen_pll_data st_pll1200c32_gpu_416 = { |
ec8d27b4 | 193 | .pdn_status = CLKGEN_FIELD(0x8E4, 0x1, 3), |
fb473862 | 194 | .pdn_ctrl = CLKGEN_FIELD(0x8E4, 0x1, 3), |
ec8d27b4 GF |
195 | .locked_status = CLKGEN_FIELD(0x90C, 0x1, 0), |
196 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
197 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
198 | .num_odfs = 0, | |
199 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
200 | .ops = &st_pll1200c32_ops, | |
201 | }; | |
202 | ||
eee8f783 GF |
203 | static const struct clkgen_pll_data st_pll3200c32_407_a0 = { |
204 | /* 407 A0 */ | |
205 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 206 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
eee8f783 GF |
207 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
208 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
209 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
210 | .num_odfs = 1, | |
211 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
212 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
213 | .ops = &stm_pll3200c32_ops, | |
214 | }; | |
215 | ||
d34e210e | 216 | static const struct clkgen_pll_data st_pll3200c32_cx_0 = { |
51306d56 GF |
217 | /* 407 C0 PLL0 */ |
218 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 219 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
51306d56 GF |
220 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
221 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
222 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
223 | .num_odfs = 1, | |
224 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
225 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
226 | .ops = &stm_pll3200c32_ops, | |
227 | }; | |
228 | ||
d34e210e | 229 | static const struct clkgen_pll_data st_pll3200c32_cx_1 = { |
51306d56 GF |
230 | /* 407 C0 PLL1 */ |
231 | .pdn_status = CLKGEN_FIELD(0x2c8, 0x1, 8), | |
fb473862 | 232 | .pdn_ctrl = CLKGEN_FIELD(0x2c8, 0x1, 8), |
51306d56 GF |
233 | .locked_status = CLKGEN_FIELD(0x2c8, 0x1, 24), |
234 | .ndiv = CLKGEN_FIELD(0x2cc, C32_NDIV_MASK, 16), | |
235 | .idf = CLKGEN_FIELD(0x2cc, C32_IDF_MASK, 0x0), | |
236 | .num_odfs = 1, | |
237 | .odf = { CLKGEN_FIELD(0x2dc, C32_ODF_MASK, 0) }, | |
238 | .odf_gate = { CLKGEN_FIELD(0x2dc, 0x1, 6) }, | |
239 | .ops = &stm_pll3200c32_ops, | |
240 | }; | |
241 | ||
aaa65d77 GF |
242 | static const struct clkgen_pll_data st_pll3200c32_407_a9 = { |
243 | /* 407 A9 */ | |
244 | .pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0), | |
fb473862 | 245 | .pdn_ctrl = CLKGEN_FIELD(0x1a8, 0x1, 0), |
aaa65d77 GF |
246 | .locked_status = CLKGEN_FIELD(0x87c, 0x1, 0), |
247 | .ndiv = CLKGEN_FIELD(0x1b0, C32_NDIV_MASK, 0), | |
248 | .idf = CLKGEN_FIELD(0x1a8, C32_IDF_MASK, 25), | |
249 | .num_odfs = 1, | |
250 | .odf = { CLKGEN_FIELD(0x1b0, C32_ODF_MASK, 8) }, | |
251 | .odf_gate = { CLKGEN_FIELD(0x1ac, 0x1, 28) }, | |
46a57afd GF |
252 | .switch2pll_en = true, |
253 | .cp = CLKGEN_FIELD(0x1a8, C32_CP_MASK, 1), | |
254 | .switch2pll = CLKGEN_FIELD(0x1a4, 0x1, 1), | |
255 | .lock = &clkgen_a9_lock, | |
256 | .ops = &stm_pll3200c32_a9_ops, | |
aaa65d77 GF |
257 | }; |
258 | ||
b9b8e614 GF |
259 | /** |
260 | * DOC: Clock Generated by PLL, rate set and enabled by bootloader | |
261 | * | |
262 | * Traits of this clock: | |
263 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | |
264 | * enable - clk_enable/disable only ensures parent is enabled | |
265 | * rate - rate is fixed. No clk_set_rate support | |
266 | * parent - fixed parent. No clk_set_parent support | |
267 | */ | |
268 | ||
269 | /** | |
270 | * PLL clock that is integrated in the ClockGenA instances on the STiH415 | |
271 | * and STiH416. | |
272 | * | |
273 | * @hw: handle between common and hardware-specific interfaces. | |
274 | * @type: PLL instance type. | |
275 | * @regs_base: base of the PLL configuration register(s). | |
276 | * | |
277 | */ | |
278 | struct clkgen_pll { | |
279 | struct clk_hw hw; | |
280 | struct clkgen_pll_data *data; | |
281 | void __iomem *regs_base; | |
46a57afd GF |
282 | spinlock_t *lock; |
283 | ||
284 | u32 ndiv; | |
285 | u32 idf; | |
286 | u32 odf; | |
287 | u32 cp; | |
b9b8e614 GF |
288 | }; |
289 | ||
290 | #define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw) | |
291 | ||
46a57afd GF |
292 | struct stm_pll { |
293 | unsigned long mdiv; | |
294 | unsigned long ndiv; | |
295 | unsigned long pdiv; | |
296 | unsigned long odf; | |
297 | unsigned long idf; | |
298 | unsigned long ldf; | |
299 | unsigned long cp; | |
300 | }; | |
301 | ||
b9b8e614 GF |
302 | static int clkgen_pll_is_locked(struct clk_hw *hw) |
303 | { | |
304 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
305 | u32 locked = CLKGEN_READ(pll, locked_status); | |
306 | ||
307 | return !!locked; | |
308 | } | |
309 | ||
310 | static int clkgen_pll_is_enabled(struct clk_hw *hw) | |
311 | { | |
312 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
313 | u32 poweroff = CLKGEN_READ(pll, pdn_status); | |
314 | return !poweroff; | |
315 | } | |
316 | ||
46a57afd | 317 | static int __clkgen_pll_enable(struct clk_hw *hw) |
fb473862 GF |
318 | { |
319 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
320 | void __iomem *base = pll->regs_base; | |
321 | struct clkgen_field *field = &pll->data->locked_status; | |
322 | int ret = 0; | |
323 | u32 reg; | |
324 | ||
325 | if (clkgen_pll_is_enabled(hw)) | |
326 | return 0; | |
327 | ||
328 | CLKGEN_WRITE(pll, pdn_ctrl, 0); | |
329 | ||
330 | ret = readl_relaxed_poll_timeout(base + field->offset, reg, | |
331 | !!((reg >> field->shift) & field->mask), 0, 10000); | |
332 | ||
46a57afd GF |
333 | if (!ret) { |
334 | if (pll->data->switch2pll_en) | |
335 | CLKGEN_WRITE(pll, switch2pll, 0); | |
336 | ||
fb473862 | 337 | pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__); |
46a57afd | 338 | } |
fb473862 GF |
339 | |
340 | return ret; | |
341 | } | |
342 | ||
46a57afd GF |
343 | static int clkgen_pll_enable(struct clk_hw *hw) |
344 | { | |
345 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
346 | unsigned long flags = 0; | |
347 | int ret = 0; | |
348 | ||
349 | if (pll->lock) | |
350 | spin_lock_irqsave(pll->lock, flags); | |
351 | ||
352 | ret = __clkgen_pll_enable(hw); | |
353 | ||
354 | if (pll->lock) | |
355 | spin_unlock_irqrestore(pll->lock, flags); | |
356 | ||
357 | return ret; | |
358 | } | |
359 | ||
360 | static void __clkgen_pll_disable(struct clk_hw *hw) | |
fb473862 GF |
361 | { |
362 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
363 | ||
364 | if (!clkgen_pll_is_enabled(hw)) | |
365 | return; | |
366 | ||
46a57afd GF |
367 | if (pll->data->switch2pll_en) |
368 | CLKGEN_WRITE(pll, switch2pll, 1); | |
369 | ||
fb473862 GF |
370 | CLKGEN_WRITE(pll, pdn_ctrl, 1); |
371 | ||
372 | pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__); | |
373 | } | |
374 | ||
46a57afd GF |
375 | static void clkgen_pll_disable(struct clk_hw *hw) |
376 | { | |
377 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
378 | unsigned long flags = 0; | |
379 | ||
380 | if (pll->lock) | |
381 | spin_lock_irqsave(pll->lock, flags); | |
382 | ||
383 | __clkgen_pll_disable(hw); | |
384 | ||
385 | if (pll->lock) | |
386 | spin_unlock_irqrestore(pll->lock, flags); | |
387 | } | |
388 | ||
8e6dd77c | 389 | static unsigned long recalc_stm_pll800c65(struct clk_hw *hw, |
b9b8e614 GF |
390 | unsigned long parent_rate) |
391 | { | |
392 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
393 | unsigned long mdiv, ndiv, pdiv; | |
394 | unsigned long rate; | |
395 | uint64_t res; | |
396 | ||
397 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
398 | return 0; | |
399 | ||
400 | pdiv = CLKGEN_READ(pll, pdiv); | |
401 | mdiv = CLKGEN_READ(pll, mdiv); | |
402 | ndiv = CLKGEN_READ(pll, ndiv); | |
403 | ||
404 | if (!mdiv) | |
405 | mdiv++; /* mdiv=0 or 1 => MDIV=1 */ | |
406 | ||
407 | res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv; | |
408 | rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv)); | |
409 | ||
836ee0f7 | 410 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
411 | |
412 | return rate; | |
413 | ||
414 | } | |
415 | ||
8e6dd77c | 416 | static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw, |
b9b8e614 GF |
417 | unsigned long parent_rate) |
418 | { | |
419 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
420 | unsigned long mdiv, ndiv; | |
421 | unsigned long rate; | |
422 | ||
423 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
424 | return 0; | |
425 | ||
426 | mdiv = CLKGEN_READ(pll, mdiv); | |
427 | ndiv = CLKGEN_READ(pll, ndiv); | |
428 | ||
429 | if (!mdiv) | |
430 | mdiv = 1; | |
431 | ||
432 | /* Note: input is divided by 1000 to avoid overflow */ | |
433 | rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000; | |
434 | ||
836ee0f7 | 435 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
436 | |
437 | return rate; | |
438 | } | |
439 | ||
46a57afd GF |
440 | static int clk_pll3200c32_get_params(unsigned long input, unsigned long output, |
441 | struct stm_pll *pll) | |
442 | { | |
443 | unsigned long i, n; | |
444 | unsigned long deviation = ~0; | |
445 | unsigned long new_freq; | |
446 | long new_deviation; | |
447 | /* Charge pump table: highest ndiv value for cp=6 to 25 */ | |
448 | static const unsigned char cp_table[] = { | |
449 | 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, | |
450 | 128, 136, 144, 152, 160, 168, 176, 184, 192 | |
451 | }; | |
452 | ||
453 | /* Output clock range: 800Mhz to 1600Mhz */ | |
454 | if (output < 800000000 || output > 1600000000) | |
455 | return -EINVAL; | |
456 | ||
457 | input /= 1000; | |
458 | output /= 1000; | |
459 | ||
460 | for (i = 1; i <= 7 && deviation; i++) { | |
461 | n = i * output / (2 * input); | |
462 | ||
463 | /* Checks */ | |
464 | if (n < 8) | |
465 | continue; | |
466 | if (n > 200) | |
467 | break; | |
468 | ||
469 | new_freq = (input * 2 * n) / i; | |
470 | ||
471 | new_deviation = abs(new_freq - output); | |
472 | ||
473 | if (!new_deviation || new_deviation < deviation) { | |
474 | pll->idf = i; | |
475 | pll->ndiv = n; | |
476 | deviation = new_deviation; | |
477 | } | |
478 | } | |
479 | ||
480 | if (deviation == ~0) /* No solution found */ | |
481 | return -EINVAL; | |
482 | ||
483 | /* Computing recommended charge pump value */ | |
484 | for (pll->cp = 6; pll->ndiv > cp_table[pll->cp-6]; (pll->cp)++) | |
485 | ; | |
486 | ||
487 | return 0; | |
488 | } | |
489 | ||
490 | static int clk_pll3200c32_get_rate(unsigned long input, struct stm_pll *pll, | |
491 | unsigned long *rate) | |
492 | { | |
493 | if (!pll->idf) | |
494 | pll->idf = 1; | |
495 | ||
496 | *rate = ((2 * (input / 1000) * pll->ndiv) / pll->idf) * 1000; | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
8e6dd77c | 501 | static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw, |
b9b8e614 GF |
502 | unsigned long parent_rate) |
503 | { | |
504 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
505 | unsigned long ndiv, idf; | |
506 | unsigned long rate = 0; | |
507 | ||
508 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
509 | return 0; | |
510 | ||
511 | ndiv = CLKGEN_READ(pll, ndiv); | |
512 | idf = CLKGEN_READ(pll, idf); | |
513 | ||
514 | if (idf) | |
515 | /* Note: input is divided to avoid overflow */ | |
516 | rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000; | |
517 | ||
836ee0f7 | 518 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
519 | |
520 | return rate; | |
521 | } | |
522 | ||
46a57afd GF |
523 | static long round_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, |
524 | unsigned long *prate) | |
525 | { | |
526 | struct stm_pll params; | |
527 | ||
528 | if (!clk_pll3200c32_get_params(*prate, rate, ¶ms)) | |
529 | clk_pll3200c32_get_rate(*prate, ¶ms, &rate); | |
530 | else { | |
531 | pr_debug("%s: %s rate %ld Invalid\n", __func__, | |
532 | __clk_get_name(hw->clk), rate); | |
533 | return 0; | |
534 | } | |
535 | ||
536 | pr_debug("%s: %s new rate %ld [ndiv=%u] [idf=%u]\n", | |
537 | __func__, __clk_get_name(hw->clk), | |
538 | rate, (unsigned int)params.ndiv, | |
539 | (unsigned int)params.idf); | |
540 | ||
541 | return rate; | |
542 | } | |
543 | ||
544 | static int set_rate_stm_pll3200c32(struct clk_hw *hw, unsigned long rate, | |
545 | unsigned long parent_rate) | |
546 | { | |
547 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
548 | struct stm_pll params; | |
549 | long hwrate = 0; | |
550 | unsigned long flags = 0; | |
551 | ||
552 | if (!rate || !parent_rate) | |
553 | return -EINVAL; | |
554 | ||
555 | if (!clk_pll3200c32_get_params(parent_rate, rate, ¶ms)) | |
556 | clk_pll3200c32_get_rate(parent_rate, ¶ms, &hwrate); | |
557 | ||
558 | pr_debug("%s: %s new rate %ld [ndiv=0x%x] [idf=0x%x]\n", | |
559 | __func__, __clk_get_name(hw->clk), | |
560 | hwrate, (unsigned int)params.ndiv, | |
561 | (unsigned int)params.idf); | |
562 | ||
563 | if (!hwrate) | |
564 | return -EINVAL; | |
565 | ||
566 | pll->ndiv = params.ndiv; | |
567 | pll->idf = params.idf; | |
568 | pll->cp = params.cp; | |
569 | ||
570 | __clkgen_pll_disable(hw); | |
571 | ||
572 | if (pll->lock) | |
573 | spin_lock_irqsave(pll->lock, flags); | |
574 | ||
575 | CLKGEN_WRITE(pll, ndiv, pll->ndiv); | |
576 | CLKGEN_WRITE(pll, idf, pll->idf); | |
577 | CLKGEN_WRITE(pll, cp, pll->cp); | |
578 | ||
579 | if (pll->lock) | |
580 | spin_unlock_irqrestore(pll->lock, flags); | |
581 | ||
582 | __clkgen_pll_enable(hw); | |
583 | ||
584 | return 0; | |
585 | } | |
586 | ||
8e6dd77c | 587 | static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw, |
b9b8e614 GF |
588 | unsigned long parent_rate) |
589 | { | |
590 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
591 | unsigned long odf, ldf, idf; | |
592 | unsigned long rate; | |
593 | ||
594 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
595 | return 0; | |
596 | ||
597 | odf = CLKGEN_READ(pll, odf[0]); | |
598 | ldf = CLKGEN_READ(pll, ldf); | |
599 | idf = CLKGEN_READ(pll, idf); | |
600 | ||
601 | if (!idf) /* idf==0 means 1 */ | |
602 | idf = 1; | |
603 | if (!odf) /* odf==0 means 1 */ | |
604 | odf = 1; | |
605 | ||
606 | /* Note: input is divided by 1000 to avoid overflow */ | |
607 | rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000; | |
608 | ||
836ee0f7 | 609 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
610 | |
611 | return rate; | |
612 | } | |
613 | ||
614 | static const struct clk_ops st_pll1600c65_ops = { | |
fb473862 GF |
615 | .enable = clkgen_pll_enable, |
616 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
617 | .is_enabled = clkgen_pll_is_enabled, |
618 | .recalc_rate = recalc_stm_pll1600c65, | |
619 | }; | |
620 | ||
621 | static const struct clk_ops st_pll800c65_ops = { | |
fb473862 GF |
622 | .enable = clkgen_pll_enable, |
623 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
624 | .is_enabled = clkgen_pll_is_enabled, |
625 | .recalc_rate = recalc_stm_pll800c65, | |
626 | }; | |
627 | ||
628 | static const struct clk_ops stm_pll3200c32_ops = { | |
fb473862 GF |
629 | .enable = clkgen_pll_enable, |
630 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
631 | .is_enabled = clkgen_pll_is_enabled, |
632 | .recalc_rate = recalc_stm_pll3200c32, | |
633 | }; | |
634 | ||
46a57afd GF |
635 | static const struct clk_ops stm_pll3200c32_a9_ops = { |
636 | .enable = clkgen_pll_enable, | |
637 | .disable = clkgen_pll_disable, | |
638 | .is_enabled = clkgen_pll_is_enabled, | |
639 | .recalc_rate = recalc_stm_pll3200c32, | |
640 | .round_rate = round_rate_stm_pll3200c32, | |
641 | .set_rate = set_rate_stm_pll3200c32, | |
642 | }; | |
643 | ||
b9b8e614 | 644 | static const struct clk_ops st_pll1200c32_ops = { |
fb473862 GF |
645 | .enable = clkgen_pll_enable, |
646 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
647 | .is_enabled = clkgen_pll_is_enabled, |
648 | .recalc_rate = recalc_stm_pll1200c32, | |
649 | }; | |
650 | ||
651 | static struct clk * __init clkgen_pll_register(const char *parent_name, | |
652 | struct clkgen_pll_data *pll_data, | |
653 | void __iomem *reg, | |
46a57afd | 654 | const char *clk_name, spinlock_t *lock) |
b9b8e614 GF |
655 | { |
656 | struct clkgen_pll *pll; | |
657 | struct clk *clk; | |
658 | struct clk_init_data init; | |
659 | ||
660 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | |
661 | if (!pll) | |
662 | return ERR_PTR(-ENOMEM); | |
663 | ||
664 | init.name = clk_name; | |
665 | init.ops = pll_data->ops; | |
666 | ||
18fee453 | 667 | init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; |
b9b8e614 GF |
668 | init.parent_names = &parent_name; |
669 | init.num_parents = 1; | |
670 | ||
671 | pll->data = pll_data; | |
672 | pll->regs_base = reg; | |
673 | pll->hw.init = &init; | |
46a57afd | 674 | pll->lock = lock; |
b9b8e614 GF |
675 | |
676 | clk = clk_register(NULL, &pll->hw); | |
677 | if (IS_ERR(clk)) { | |
678 | kfree(pll); | |
679 | return clk; | |
680 | } | |
681 | ||
682 | pr_debug("%s: parent %s rate %lu\n", | |
683 | __clk_get_name(clk), | |
684 | __clk_get_name(clk_get_parent(clk)), | |
685 | clk_get_rate(clk)); | |
686 | ||
687 | return clk; | |
688 | } | |
689 | ||
690 | static struct clk * __init clkgen_c65_lsdiv_register(const char *parent_name, | |
691 | const char *clk_name) | |
692 | { | |
693 | struct clk *clk; | |
694 | ||
695 | clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, 1, 2); | |
696 | if (IS_ERR(clk)) | |
697 | return clk; | |
698 | ||
699 | pr_debug("%s: parent %s rate %lu\n", | |
700 | __clk_get_name(clk), | |
701 | __clk_get_name(clk_get_parent(clk)), | |
702 | clk_get_rate(clk)); | |
703 | return clk; | |
704 | } | |
705 | ||
706 | static void __iomem * __init clkgen_get_register_base( | |
707 | struct device_node *np) | |
708 | { | |
709 | struct device_node *pnode; | |
710 | void __iomem *reg = NULL; | |
711 | ||
712 | pnode = of_get_parent(np); | |
713 | if (!pnode) | |
714 | return NULL; | |
715 | ||
716 | reg = of_iomap(pnode, 0); | |
717 | ||
718 | of_node_put(pnode); | |
719 | return reg; | |
720 | } | |
721 | ||
722 | #define CLKGENAx_PLL0_OFFSET 0x0 | |
723 | #define CLKGENAx_PLL1_OFFSET 0x4 | |
724 | ||
725 | static void __init clkgena_c65_pll_setup(struct device_node *np) | |
726 | { | |
727 | const int num_pll_outputs = 3; | |
728 | struct clk_onecell_data *clk_data; | |
729 | const char *parent_name; | |
730 | void __iomem *reg; | |
731 | const char *clk_name; | |
732 | ||
733 | parent_name = of_clk_get_parent_name(np, 0); | |
734 | if (!parent_name) | |
735 | return; | |
736 | ||
737 | reg = clkgen_get_register_base(np); | |
738 | if (!reg) | |
739 | return; | |
740 | ||
741 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
742 | if (!clk_data) | |
743 | return; | |
744 | ||
745 | clk_data->clk_num = num_pll_outputs; | |
746 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
747 | GFP_KERNEL); | |
748 | ||
749 | if (!clk_data->clks) | |
750 | goto err; | |
751 | ||
752 | if (of_property_read_string_index(np, "clock-output-names", | |
753 | 0, &clk_name)) | |
754 | goto err; | |
755 | ||
756 | /* | |
757 | * PLL0 HS (high speed) output | |
758 | */ | |
759 | clk_data->clks[0] = clkgen_pll_register(parent_name, | |
dc4febef | 760 | (struct clkgen_pll_data *) &st_pll1600c65_ax, |
46a57afd | 761 | reg + CLKGENAx_PLL0_OFFSET, clk_name, NULL); |
b9b8e614 GF |
762 | |
763 | if (IS_ERR(clk_data->clks[0])) | |
764 | goto err; | |
765 | ||
766 | if (of_property_read_string_index(np, "clock-output-names", | |
767 | 1, &clk_name)) | |
768 | goto err; | |
769 | ||
770 | /* | |
771 | * PLL0 LS (low speed) output, which is a fixed divide by 2 of the | |
772 | * high speed output. | |
773 | */ | |
774 | clk_data->clks[1] = clkgen_c65_lsdiv_register(__clk_get_name | |
775 | (clk_data->clks[0]), | |
776 | clk_name); | |
777 | ||
778 | if (IS_ERR(clk_data->clks[1])) | |
779 | goto err; | |
780 | ||
781 | if (of_property_read_string_index(np, "clock-output-names", | |
782 | 2, &clk_name)) | |
783 | goto err; | |
784 | ||
785 | /* | |
786 | * PLL1 output | |
787 | */ | |
788 | clk_data->clks[2] = clkgen_pll_register(parent_name, | |
dc4febef | 789 | (struct clkgen_pll_data *) &st_pll800c65_ax, |
46a57afd | 790 | reg + CLKGENAx_PLL1_OFFSET, clk_name, NULL); |
b9b8e614 GF |
791 | |
792 | if (IS_ERR(clk_data->clks[2])) | |
793 | goto err; | |
794 | ||
795 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
796 | return; | |
797 | ||
798 | err: | |
799 | kfree(clk_data->clks); | |
800 | kfree(clk_data); | |
801 | } | |
802 | CLK_OF_DECLARE(clkgena_c65_plls, | |
803 | "st,clkgena-plls-c65", clkgena_c65_pll_setup); | |
804 | ||
805 | static struct clk * __init clkgen_odf_register(const char *parent_name, | |
8e6dd77c | 806 | void __iomem *reg, |
b9b8e614 GF |
807 | struct clkgen_pll_data *pll_data, |
808 | int odf, | |
809 | spinlock_t *odf_lock, | |
810 | const char *odf_name) | |
811 | { | |
812 | struct clk *clk; | |
813 | unsigned long flags; | |
814 | struct clk_gate *gate; | |
815 | struct clk_divider *div; | |
816 | ||
46a57afd | 817 | flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT; |
b9b8e614 GF |
818 | |
819 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | |
820 | if (!gate) | |
821 | return ERR_PTR(-ENOMEM); | |
822 | ||
823 | gate->flags = CLK_GATE_SET_TO_DISABLE; | |
824 | gate->reg = reg + pll_data->odf_gate[odf].offset; | |
825 | gate->bit_idx = pll_data->odf_gate[odf].shift; | |
826 | gate->lock = odf_lock; | |
827 | ||
828 | div = kzalloc(sizeof(*div), GFP_KERNEL); | |
72b1c2c3 VI |
829 | if (!div) { |
830 | kfree(gate); | |
b9b8e614 | 831 | return ERR_PTR(-ENOMEM); |
72b1c2c3 | 832 | } |
b9b8e614 GF |
833 | |
834 | div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; | |
835 | div->reg = reg + pll_data->odf[odf].offset; | |
836 | div->shift = pll_data->odf[odf].shift; | |
837 | div->width = fls(pll_data->odf[odf].mask); | |
838 | div->lock = odf_lock; | |
839 | ||
840 | clk = clk_register_composite(NULL, odf_name, &parent_name, 1, | |
841 | NULL, NULL, | |
842 | &div->hw, &clk_divider_ops, | |
843 | &gate->hw, &clk_gate_ops, | |
844 | flags); | |
845 | if (IS_ERR(clk)) | |
846 | return clk; | |
847 | ||
848 | pr_debug("%s: parent %s rate %lu\n", | |
849 | __clk_get_name(clk), | |
850 | __clk_get_name(clk_get_parent(clk)), | |
851 | clk_get_rate(clk)); | |
852 | return clk; | |
853 | } | |
854 | ||
f375573c | 855 | static const struct of_device_id c32_pll_of_match[] = { |
b9b8e614 GF |
856 | { |
857 | .compatible = "st,plls-c32-a1x-0", | |
858 | .data = &st_pll3200c32_a1x_0, | |
859 | }, | |
860 | { | |
861 | .compatible = "st,plls-c32-a1x-1", | |
862 | .data = &st_pll3200c32_a1x_1, | |
863 | }, | |
ec8d27b4 GF |
864 | { |
865 | .compatible = "st,stih415-plls-c32-a9", | |
866 | .data = &st_pll3200c32_a9_415, | |
867 | }, | |
868 | { | |
869 | .compatible = "st,stih415-plls-c32-ddr", | |
870 | .data = &st_pll3200c32_ddr_415, | |
871 | }, | |
872 | { | |
873 | .compatible = "st,stih416-plls-c32-a9", | |
874 | .data = &st_pll3200c32_a9_416, | |
875 | }, | |
876 | { | |
877 | .compatible = "st,stih416-plls-c32-ddr", | |
878 | .data = &st_pll3200c32_ddr_416, | |
879 | }, | |
eee8f783 GF |
880 | { |
881 | .compatible = "st,stih407-plls-c32-a0", | |
882 | .data = &st_pll3200c32_407_a0, | |
883 | }, | |
51306d56 | 884 | { |
d34e210e GF |
885 | .compatible = "st,plls-c32-cx_0", |
886 | .data = &st_pll3200c32_cx_0, | |
51306d56 GF |
887 | }, |
888 | { | |
d34e210e GF |
889 | .compatible = "st,plls-c32-cx_1", |
890 | .data = &st_pll3200c32_cx_1, | |
51306d56 | 891 | }, |
aaa65d77 GF |
892 | { |
893 | .compatible = "st,stih407-plls-c32-a9", | |
894 | .data = &st_pll3200c32_407_a9, | |
895 | }, | |
b9b8e614 GF |
896 | {} |
897 | }; | |
898 | ||
899 | static void __init clkgen_c32_pll_setup(struct device_node *np) | |
900 | { | |
901 | const struct of_device_id *match; | |
902 | struct clk *clk; | |
903 | const char *parent_name, *pll_name; | |
904 | void __iomem *pll_base; | |
905 | int num_odfs, odf; | |
906 | struct clk_onecell_data *clk_data; | |
907 | struct clkgen_pll_data *data; | |
908 | ||
909 | match = of_match_node(c32_pll_of_match, np); | |
910 | if (!match) { | |
911 | pr_err("%s: No matching data\n", __func__); | |
912 | return; | |
913 | } | |
914 | ||
915 | data = (struct clkgen_pll_data *) match->data; | |
916 | ||
917 | parent_name = of_clk_get_parent_name(np, 0); | |
918 | if (!parent_name) | |
919 | return; | |
920 | ||
921 | pll_base = clkgen_get_register_base(np); | |
922 | if (!pll_base) | |
923 | return; | |
924 | ||
46a57afd GF |
925 | clk = clkgen_pll_register(parent_name, data, pll_base, np->name, |
926 | data->lock); | |
b9b8e614 GF |
927 | if (IS_ERR(clk)) |
928 | return; | |
929 | ||
930 | pll_name = __clk_get_name(clk); | |
931 | ||
932 | num_odfs = data->num_odfs; | |
933 | ||
934 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
935 | if (!clk_data) | |
936 | return; | |
937 | ||
938 | clk_data->clk_num = num_odfs; | |
939 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
940 | GFP_KERNEL); | |
941 | ||
942 | if (!clk_data->clks) | |
943 | goto err; | |
944 | ||
945 | for (odf = 0; odf < num_odfs; odf++) { | |
946 | struct clk *clk; | |
947 | const char *clk_name; | |
948 | ||
949 | if (of_property_read_string_index(np, "clock-output-names", | |
950 | odf, &clk_name)) | |
951 | return; | |
952 | ||
953 | clk = clkgen_odf_register(pll_name, pll_base, data, | |
954 | odf, &clkgena_c32_odf_lock, clk_name); | |
955 | if (IS_ERR(clk)) | |
956 | goto err; | |
957 | ||
958 | clk_data->clks[odf] = clk; | |
959 | } | |
960 | ||
961 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
962 | return; | |
963 | ||
964 | err: | |
965 | kfree(pll_name); | |
966 | kfree(clk_data->clks); | |
967 | kfree(clk_data); | |
968 | } | |
969 | CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup); | |
ec8d27b4 | 970 | |
f375573c | 971 | static const struct of_device_id c32_gpu_pll_of_match[] = { |
ec8d27b4 GF |
972 | { |
973 | .compatible = "st,stih415-gpu-pll-c32", | |
974 | .data = &st_pll1200c32_gpu_415, | |
975 | }, | |
976 | { | |
977 | .compatible = "st,stih416-gpu-pll-c32", | |
978 | .data = &st_pll1200c32_gpu_416, | |
979 | }, | |
70040b35 | 980 | {} |
ec8d27b4 GF |
981 | }; |
982 | ||
983 | static void __init clkgengpu_c32_pll_setup(struct device_node *np) | |
984 | { | |
985 | const struct of_device_id *match; | |
986 | struct clk *clk; | |
987 | const char *parent_name; | |
988 | void __iomem *reg; | |
989 | const char *clk_name; | |
990 | struct clkgen_pll_data *data; | |
991 | ||
992 | match = of_match_node(c32_gpu_pll_of_match, np); | |
993 | if (!match) { | |
994 | pr_err("%s: No matching data\n", __func__); | |
995 | return; | |
996 | } | |
997 | ||
998 | data = (struct clkgen_pll_data *)match->data; | |
999 | ||
1000 | parent_name = of_clk_get_parent_name(np, 0); | |
1001 | if (!parent_name) | |
1002 | return; | |
1003 | ||
1004 | reg = clkgen_get_register_base(np); | |
1005 | if (!reg) | |
1006 | return; | |
1007 | ||
1008 | if (of_property_read_string_index(np, "clock-output-names", | |
1009 | 0, &clk_name)) | |
1010 | return; | |
1011 | ||
1012 | /* | |
1013 | * PLL 1200MHz output | |
1014 | */ | |
46a57afd | 1015 | clk = clkgen_pll_register(parent_name, data, reg, clk_name, data->lock); |
ec8d27b4 GF |
1016 | |
1017 | if (!IS_ERR(clk)) | |
1018 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | |
1019 | ||
1020 | return; | |
1021 | } | |
1022 | CLK_OF_DECLARE(clkgengpu_c32_pll, | |
1023 | "st,clkgengpu-pll-c32", clkgengpu_c32_pll_setup); |