]>
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); | |
26 | ||
27 | /* | |
28 | * Common PLL configuration register bits for PLL800 and PLL1600 C65 | |
29 | */ | |
30 | #define C65_MDIV_PLL800_MASK (0xff) | |
31 | #define C65_MDIV_PLL1600_MASK (0x7) | |
32 | #define C65_NDIV_MASK (0xff) | |
33 | #define C65_PDIV_MASK (0x7) | |
34 | ||
35 | /* | |
36 | * PLL configuration register bits for PLL3200 C32 | |
37 | */ | |
38 | #define C32_NDIV_MASK (0xff) | |
39 | #define C32_IDF_MASK (0x7) | |
40 | #define C32_ODF_MASK (0x3f) | |
41 | #define C32_LDF_MASK (0x7f) | |
42 | ||
43 | #define C32_MAX_ODFS (4) | |
44 | ||
45 | struct clkgen_pll_data { | |
46 | struct clkgen_field pdn_status; | |
fb473862 | 47 | struct clkgen_field pdn_ctrl; |
b9b8e614 GF |
48 | struct clkgen_field locked_status; |
49 | struct clkgen_field mdiv; | |
50 | struct clkgen_field ndiv; | |
51 | struct clkgen_field pdiv; | |
52 | struct clkgen_field idf; | |
53 | struct clkgen_field ldf; | |
54 | unsigned int num_odfs; | |
55 | struct clkgen_field odf[C32_MAX_ODFS]; | |
56 | struct clkgen_field odf_gate[C32_MAX_ODFS]; | |
57 | const struct clk_ops *ops; | |
58 | }; | |
59 | ||
60 | static const struct clk_ops st_pll1600c65_ops; | |
61 | static const struct clk_ops st_pll800c65_ops; | |
62 | static const struct clk_ops stm_pll3200c32_ops; | |
63 | static const struct clk_ops st_pll1200c32_ops; | |
64 | ||
dc4febef | 65 | static const struct clkgen_pll_data st_pll1600c65_ax = { |
b9b8e614 | 66 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 67 | .pdn_ctrl = CLKGEN_FIELD(0x10, 0x1, 0), |
b9b8e614 GF |
68 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
69 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL1600_MASK, 0), | |
70 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
71 | .ops = &st_pll1600c65_ops | |
72 | }; | |
73 | ||
dc4febef | 74 | static const struct clkgen_pll_data st_pll800c65_ax = { |
b9b8e614 | 75 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 19), |
fb473862 | 76 | .pdn_ctrl = CLKGEN_FIELD(0xC, 0x1, 1), |
b9b8e614 GF |
77 | .locked_status = CLKGEN_FIELD(0x0, 0x1, 31), |
78 | .mdiv = CLKGEN_FIELD(0x0, C65_MDIV_PLL800_MASK, 0), | |
79 | .ndiv = CLKGEN_FIELD(0x0, C65_NDIV_MASK, 8), | |
80 | .pdiv = CLKGEN_FIELD(0x0, C65_PDIV_MASK, 16), | |
81 | .ops = &st_pll800c65_ops | |
82 | }; | |
83 | ||
dc4febef | 84 | static const struct clkgen_pll_data st_pll3200c32_a1x_0 = { |
b9b8e614 | 85 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 31), |
fb473862 | 86 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 0), |
b9b8e614 GF |
87 | .locked_status = CLKGEN_FIELD(0x4, 0x1, 31), |
88 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 0x0), | |
89 | .idf = CLKGEN_FIELD(0x4, C32_IDF_MASK, 0x0), | |
90 | .num_odfs = 4, | |
91 | .odf = { CLKGEN_FIELD(0x54, C32_ODF_MASK, 4), | |
92 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 10), | |
93 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 16), | |
94 | CLKGEN_FIELD(0x54, C32_ODF_MASK, 22) }, | |
95 | .odf_gate = { CLKGEN_FIELD(0x54, 0x1, 0), | |
96 | CLKGEN_FIELD(0x54, 0x1, 1), | |
97 | CLKGEN_FIELD(0x54, 0x1, 2), | |
98 | CLKGEN_FIELD(0x54, 0x1, 3) }, | |
99 | .ops = &stm_pll3200c32_ops, | |
100 | }; | |
101 | ||
dc4febef | 102 | static const struct clkgen_pll_data st_pll3200c32_a1x_1 = { |
b9b8e614 | 103 | .pdn_status = CLKGEN_FIELD(0xC, 0x1, 31), |
fb473862 | 104 | .pdn_ctrl = CLKGEN_FIELD(0x18, 0x1, 1), |
b9b8e614 GF |
105 | .locked_status = CLKGEN_FIELD(0x10, 0x1, 31), |
106 | .ndiv = CLKGEN_FIELD(0xC, C32_NDIV_MASK, 0x0), | |
107 | .idf = CLKGEN_FIELD(0x10, C32_IDF_MASK, 0x0), | |
108 | .num_odfs = 4, | |
109 | .odf = { CLKGEN_FIELD(0x58, C32_ODF_MASK, 4), | |
110 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 10), | |
111 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 16), | |
112 | CLKGEN_FIELD(0x58, C32_ODF_MASK, 22) }, | |
113 | .odf_gate = { CLKGEN_FIELD(0x58, 0x1, 0), | |
114 | CLKGEN_FIELD(0x58, 0x1, 1), | |
115 | CLKGEN_FIELD(0x58, 0x1, 2), | |
116 | CLKGEN_FIELD(0x58, 0x1, 3) }, | |
117 | .ops = &stm_pll3200c32_ops, | |
118 | }; | |
119 | ||
ec8d27b4 | 120 | /* 415 specific */ |
dc4febef | 121 | static const struct clkgen_pll_data st_pll3200c32_a9_415 = { |
ec8d27b4 | 122 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 123 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
124 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
125 | .ndiv = CLKGEN_FIELD(0x0, C32_NDIV_MASK, 9), | |
126 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 22), | |
127 | .num_odfs = 1, | |
128 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 3) }, | |
129 | .odf_gate = { CLKGEN_FIELD(0x0, 0x1, 28) }, | |
130 | .ops = &stm_pll3200c32_ops, | |
131 | }; | |
132 | ||
dc4febef | 133 | static const struct clkgen_pll_data st_pll3200c32_ddr_415 = { |
ec8d27b4 | 134 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 135 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
136 | .locked_status = CLKGEN_FIELD(0x100, 0x1, 0), |
137 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
138 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
139 | .num_odfs = 2, | |
140 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
141 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
142 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
143 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
144 | .ops = &stm_pll3200c32_ops, | |
145 | }; | |
146 | ||
dc4febef | 147 | static const struct clkgen_pll_data st_pll1200c32_gpu_415 = { |
fb473862 GF |
148 | .pdn_status = CLKGEN_FIELD(0x4, 0x1, 0), |
149 | .pdn_ctrl = CLKGEN_FIELD(0x4, 0x1, 0), | |
ec8d27b4 GF |
150 | .locked_status = CLKGEN_FIELD(0x168, 0x1, 0), |
151 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
152 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
153 | .num_odfs = 0, | |
154 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
155 | .ops = &st_pll1200c32_ops, | |
156 | }; | |
157 | ||
158 | /* 416 specific */ | |
dc4febef | 159 | static const struct clkgen_pll_data st_pll3200c32_a9_416 = { |
ec8d27b4 | 160 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 161 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
162 | .locked_status = CLKGEN_FIELD(0x6C, 0x1, 0), |
163 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
164 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
165 | .num_odfs = 1, | |
166 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8) }, | |
167 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28) }, | |
168 | .ops = &stm_pll3200c32_ops, | |
169 | }; | |
170 | ||
dc4febef | 171 | static const struct clkgen_pll_data st_pll3200c32_ddr_416 = { |
ec8d27b4 | 172 | .pdn_status = CLKGEN_FIELD(0x0, 0x1, 0), |
fb473862 | 173 | .pdn_ctrl = CLKGEN_FIELD(0x0, 0x1, 0), |
ec8d27b4 GF |
174 | .locked_status = CLKGEN_FIELD(0x10C, 0x1, 0), |
175 | .ndiv = CLKGEN_FIELD(0x8, C32_NDIV_MASK, 0), | |
176 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 25), | |
177 | .num_odfs = 2, | |
178 | .odf = { CLKGEN_FIELD(0x8, C32_ODF_MASK, 8), | |
179 | CLKGEN_FIELD(0x8, C32_ODF_MASK, 14) }, | |
180 | .odf_gate = { CLKGEN_FIELD(0x4, 0x1, 28), | |
181 | CLKGEN_FIELD(0x4, 0x1, 29) }, | |
182 | .ops = &stm_pll3200c32_ops, | |
183 | }; | |
184 | ||
dc4febef | 185 | static const struct clkgen_pll_data st_pll1200c32_gpu_416 = { |
ec8d27b4 | 186 | .pdn_status = CLKGEN_FIELD(0x8E4, 0x1, 3), |
fb473862 | 187 | .pdn_ctrl = CLKGEN_FIELD(0x8E4, 0x1, 3), |
ec8d27b4 GF |
188 | .locked_status = CLKGEN_FIELD(0x90C, 0x1, 0), |
189 | .ldf = CLKGEN_FIELD(0x0, C32_LDF_MASK, 3), | |
190 | .idf = CLKGEN_FIELD(0x0, C32_IDF_MASK, 0), | |
191 | .num_odfs = 0, | |
192 | .odf = { CLKGEN_FIELD(0x0, C32_ODF_MASK, 10) }, | |
193 | .ops = &st_pll1200c32_ops, | |
194 | }; | |
195 | ||
eee8f783 GF |
196 | static const struct clkgen_pll_data st_pll3200c32_407_a0 = { |
197 | /* 407 A0 */ | |
198 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 199 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
eee8f783 GF |
200 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
201 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
202 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
203 | .num_odfs = 1, | |
204 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
205 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
206 | .ops = &stm_pll3200c32_ops, | |
207 | }; | |
208 | ||
d34e210e | 209 | static const struct clkgen_pll_data st_pll3200c32_cx_0 = { |
51306d56 GF |
210 | /* 407 C0 PLL0 */ |
211 | .pdn_status = CLKGEN_FIELD(0x2a0, 0x1, 8), | |
fb473862 | 212 | .pdn_ctrl = CLKGEN_FIELD(0x2a0, 0x1, 8), |
51306d56 GF |
213 | .locked_status = CLKGEN_FIELD(0x2a0, 0x1, 24), |
214 | .ndiv = CLKGEN_FIELD(0x2a4, C32_NDIV_MASK, 16), | |
215 | .idf = CLKGEN_FIELD(0x2a4, C32_IDF_MASK, 0x0), | |
216 | .num_odfs = 1, | |
217 | .odf = { CLKGEN_FIELD(0x2b4, C32_ODF_MASK, 0) }, | |
218 | .odf_gate = { CLKGEN_FIELD(0x2b4, 0x1, 6) }, | |
219 | .ops = &stm_pll3200c32_ops, | |
220 | }; | |
221 | ||
d34e210e | 222 | static const struct clkgen_pll_data st_pll3200c32_cx_1 = { |
51306d56 GF |
223 | /* 407 C0 PLL1 */ |
224 | .pdn_status = CLKGEN_FIELD(0x2c8, 0x1, 8), | |
fb473862 | 225 | .pdn_ctrl = CLKGEN_FIELD(0x2c8, 0x1, 8), |
51306d56 GF |
226 | .locked_status = CLKGEN_FIELD(0x2c8, 0x1, 24), |
227 | .ndiv = CLKGEN_FIELD(0x2cc, C32_NDIV_MASK, 16), | |
228 | .idf = CLKGEN_FIELD(0x2cc, C32_IDF_MASK, 0x0), | |
229 | .num_odfs = 1, | |
230 | .odf = { CLKGEN_FIELD(0x2dc, C32_ODF_MASK, 0) }, | |
231 | .odf_gate = { CLKGEN_FIELD(0x2dc, 0x1, 6) }, | |
232 | .ops = &stm_pll3200c32_ops, | |
233 | }; | |
234 | ||
aaa65d77 GF |
235 | static const struct clkgen_pll_data st_pll3200c32_407_a9 = { |
236 | /* 407 A9 */ | |
237 | .pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0), | |
fb473862 | 238 | .pdn_ctrl = CLKGEN_FIELD(0x1a8, 0x1, 0), |
aaa65d77 GF |
239 | .locked_status = CLKGEN_FIELD(0x87c, 0x1, 0), |
240 | .ndiv = CLKGEN_FIELD(0x1b0, C32_NDIV_MASK, 0), | |
241 | .idf = CLKGEN_FIELD(0x1a8, C32_IDF_MASK, 25), | |
242 | .num_odfs = 1, | |
243 | .odf = { CLKGEN_FIELD(0x1b0, C32_ODF_MASK, 8) }, | |
244 | .odf_gate = { CLKGEN_FIELD(0x1ac, 0x1, 28) }, | |
245 | .ops = &stm_pll3200c32_ops, | |
246 | }; | |
247 | ||
b9b8e614 GF |
248 | /** |
249 | * DOC: Clock Generated by PLL, rate set and enabled by bootloader | |
250 | * | |
251 | * Traits of this clock: | |
252 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | |
253 | * enable - clk_enable/disable only ensures parent is enabled | |
254 | * rate - rate is fixed. No clk_set_rate support | |
255 | * parent - fixed parent. No clk_set_parent support | |
256 | */ | |
257 | ||
258 | /** | |
259 | * PLL clock that is integrated in the ClockGenA instances on the STiH415 | |
260 | * and STiH416. | |
261 | * | |
262 | * @hw: handle between common and hardware-specific interfaces. | |
263 | * @type: PLL instance type. | |
264 | * @regs_base: base of the PLL configuration register(s). | |
265 | * | |
266 | */ | |
267 | struct clkgen_pll { | |
268 | struct clk_hw hw; | |
269 | struct clkgen_pll_data *data; | |
270 | void __iomem *regs_base; | |
271 | }; | |
272 | ||
273 | #define to_clkgen_pll(_hw) container_of(_hw, struct clkgen_pll, hw) | |
274 | ||
275 | static int clkgen_pll_is_locked(struct clk_hw *hw) | |
276 | { | |
277 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
278 | u32 locked = CLKGEN_READ(pll, locked_status); | |
279 | ||
280 | return !!locked; | |
281 | } | |
282 | ||
283 | static int clkgen_pll_is_enabled(struct clk_hw *hw) | |
284 | { | |
285 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
286 | u32 poweroff = CLKGEN_READ(pll, pdn_status); | |
287 | return !poweroff; | |
288 | } | |
289 | ||
fb473862 GF |
290 | static int clkgen_pll_enable(struct clk_hw *hw) |
291 | { | |
292 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
293 | void __iomem *base = pll->regs_base; | |
294 | struct clkgen_field *field = &pll->data->locked_status; | |
295 | int ret = 0; | |
296 | u32 reg; | |
297 | ||
298 | if (clkgen_pll_is_enabled(hw)) | |
299 | return 0; | |
300 | ||
301 | CLKGEN_WRITE(pll, pdn_ctrl, 0); | |
302 | ||
303 | ret = readl_relaxed_poll_timeout(base + field->offset, reg, | |
304 | !!((reg >> field->shift) & field->mask), 0, 10000); | |
305 | ||
306 | if (!ret) | |
307 | pr_debug("%s:%s enabled\n", __clk_get_name(hw->clk), __func__); | |
308 | ||
309 | return ret; | |
310 | } | |
311 | ||
312 | static void clkgen_pll_disable(struct clk_hw *hw) | |
313 | { | |
314 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
315 | ||
316 | if (!clkgen_pll_is_enabled(hw)) | |
317 | return; | |
318 | ||
319 | CLKGEN_WRITE(pll, pdn_ctrl, 1); | |
320 | ||
321 | pr_debug("%s:%s disabled\n", __clk_get_name(hw->clk), __func__); | |
322 | } | |
323 | ||
8e6dd77c | 324 | static unsigned long recalc_stm_pll800c65(struct clk_hw *hw, |
b9b8e614 GF |
325 | unsigned long parent_rate) |
326 | { | |
327 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
328 | unsigned long mdiv, ndiv, pdiv; | |
329 | unsigned long rate; | |
330 | uint64_t res; | |
331 | ||
332 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
333 | return 0; | |
334 | ||
335 | pdiv = CLKGEN_READ(pll, pdiv); | |
336 | mdiv = CLKGEN_READ(pll, mdiv); | |
337 | ndiv = CLKGEN_READ(pll, ndiv); | |
338 | ||
339 | if (!mdiv) | |
340 | mdiv++; /* mdiv=0 or 1 => MDIV=1 */ | |
341 | ||
342 | res = (uint64_t)2 * (uint64_t)parent_rate * (uint64_t)ndiv; | |
343 | rate = (unsigned long)div64_u64(res, mdiv * (1 << pdiv)); | |
344 | ||
836ee0f7 | 345 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
346 | |
347 | return rate; | |
348 | ||
349 | } | |
350 | ||
8e6dd77c | 351 | static unsigned long recalc_stm_pll1600c65(struct clk_hw *hw, |
b9b8e614 GF |
352 | unsigned long parent_rate) |
353 | { | |
354 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
355 | unsigned long mdiv, ndiv; | |
356 | unsigned long rate; | |
357 | ||
358 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
359 | return 0; | |
360 | ||
361 | mdiv = CLKGEN_READ(pll, mdiv); | |
362 | ndiv = CLKGEN_READ(pll, ndiv); | |
363 | ||
364 | if (!mdiv) | |
365 | mdiv = 1; | |
366 | ||
367 | /* Note: input is divided by 1000 to avoid overflow */ | |
368 | rate = ((2 * (parent_rate / 1000) * ndiv) / mdiv) * 1000; | |
369 | ||
836ee0f7 | 370 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
371 | |
372 | return rate; | |
373 | } | |
374 | ||
8e6dd77c | 375 | static unsigned long recalc_stm_pll3200c32(struct clk_hw *hw, |
b9b8e614 GF |
376 | unsigned long parent_rate) |
377 | { | |
378 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
379 | unsigned long ndiv, idf; | |
380 | unsigned long rate = 0; | |
381 | ||
382 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
383 | return 0; | |
384 | ||
385 | ndiv = CLKGEN_READ(pll, ndiv); | |
386 | idf = CLKGEN_READ(pll, idf); | |
387 | ||
388 | if (idf) | |
389 | /* Note: input is divided to avoid overflow */ | |
390 | rate = ((2 * (parent_rate/1000) * ndiv) / idf) * 1000; | |
391 | ||
836ee0f7 | 392 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
393 | |
394 | return rate; | |
395 | } | |
396 | ||
8e6dd77c | 397 | static unsigned long recalc_stm_pll1200c32(struct clk_hw *hw, |
b9b8e614 GF |
398 | unsigned long parent_rate) |
399 | { | |
400 | struct clkgen_pll *pll = to_clkgen_pll(hw); | |
401 | unsigned long odf, ldf, idf; | |
402 | unsigned long rate; | |
403 | ||
404 | if (!clkgen_pll_is_enabled(hw) || !clkgen_pll_is_locked(hw)) | |
405 | return 0; | |
406 | ||
407 | odf = CLKGEN_READ(pll, odf[0]); | |
408 | ldf = CLKGEN_READ(pll, ldf); | |
409 | idf = CLKGEN_READ(pll, idf); | |
410 | ||
411 | if (!idf) /* idf==0 means 1 */ | |
412 | idf = 1; | |
413 | if (!odf) /* odf==0 means 1 */ | |
414 | odf = 1; | |
415 | ||
416 | /* Note: input is divided by 1000 to avoid overflow */ | |
417 | rate = (((parent_rate / 1000) * ldf) / (odf * idf)) * 1000; | |
418 | ||
836ee0f7 | 419 | pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); |
b9b8e614 GF |
420 | |
421 | return rate; | |
422 | } | |
423 | ||
424 | static const struct clk_ops st_pll1600c65_ops = { | |
fb473862 GF |
425 | .enable = clkgen_pll_enable, |
426 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
427 | .is_enabled = clkgen_pll_is_enabled, |
428 | .recalc_rate = recalc_stm_pll1600c65, | |
429 | }; | |
430 | ||
431 | static const struct clk_ops st_pll800c65_ops = { | |
fb473862 GF |
432 | .enable = clkgen_pll_enable, |
433 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
434 | .is_enabled = clkgen_pll_is_enabled, |
435 | .recalc_rate = recalc_stm_pll800c65, | |
436 | }; | |
437 | ||
438 | static const struct clk_ops stm_pll3200c32_ops = { | |
fb473862 GF |
439 | .enable = clkgen_pll_enable, |
440 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
441 | .is_enabled = clkgen_pll_is_enabled, |
442 | .recalc_rate = recalc_stm_pll3200c32, | |
443 | }; | |
444 | ||
445 | static const struct clk_ops st_pll1200c32_ops = { | |
fb473862 GF |
446 | .enable = clkgen_pll_enable, |
447 | .disable = clkgen_pll_disable, | |
b9b8e614 GF |
448 | .is_enabled = clkgen_pll_is_enabled, |
449 | .recalc_rate = recalc_stm_pll1200c32, | |
450 | }; | |
451 | ||
452 | static struct clk * __init clkgen_pll_register(const char *parent_name, | |
453 | struct clkgen_pll_data *pll_data, | |
454 | void __iomem *reg, | |
455 | const char *clk_name) | |
456 | { | |
457 | struct clkgen_pll *pll; | |
458 | struct clk *clk; | |
459 | struct clk_init_data init; | |
460 | ||
461 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | |
462 | if (!pll) | |
463 | return ERR_PTR(-ENOMEM); | |
464 | ||
465 | init.name = clk_name; | |
466 | init.ops = pll_data->ops; | |
467 | ||
18fee453 | 468 | init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; |
b9b8e614 GF |
469 | init.parent_names = &parent_name; |
470 | init.num_parents = 1; | |
471 | ||
472 | pll->data = pll_data; | |
473 | pll->regs_base = reg; | |
474 | pll->hw.init = &init; | |
475 | ||
476 | clk = clk_register(NULL, &pll->hw); | |
477 | if (IS_ERR(clk)) { | |
478 | kfree(pll); | |
479 | return clk; | |
480 | } | |
481 | ||
482 | pr_debug("%s: parent %s rate %lu\n", | |
483 | __clk_get_name(clk), | |
484 | __clk_get_name(clk_get_parent(clk)), | |
485 | clk_get_rate(clk)); | |
486 | ||
487 | return clk; | |
488 | } | |
489 | ||
490 | static struct clk * __init clkgen_c65_lsdiv_register(const char *parent_name, | |
491 | const char *clk_name) | |
492 | { | |
493 | struct clk *clk; | |
494 | ||
495 | clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, 1, 2); | |
496 | if (IS_ERR(clk)) | |
497 | return clk; | |
498 | ||
499 | pr_debug("%s: parent %s rate %lu\n", | |
500 | __clk_get_name(clk), | |
501 | __clk_get_name(clk_get_parent(clk)), | |
502 | clk_get_rate(clk)); | |
503 | return clk; | |
504 | } | |
505 | ||
506 | static void __iomem * __init clkgen_get_register_base( | |
507 | struct device_node *np) | |
508 | { | |
509 | struct device_node *pnode; | |
510 | void __iomem *reg = NULL; | |
511 | ||
512 | pnode = of_get_parent(np); | |
513 | if (!pnode) | |
514 | return NULL; | |
515 | ||
516 | reg = of_iomap(pnode, 0); | |
517 | ||
518 | of_node_put(pnode); | |
519 | return reg; | |
520 | } | |
521 | ||
522 | #define CLKGENAx_PLL0_OFFSET 0x0 | |
523 | #define CLKGENAx_PLL1_OFFSET 0x4 | |
524 | ||
525 | static void __init clkgena_c65_pll_setup(struct device_node *np) | |
526 | { | |
527 | const int num_pll_outputs = 3; | |
528 | struct clk_onecell_data *clk_data; | |
529 | const char *parent_name; | |
530 | void __iomem *reg; | |
531 | const char *clk_name; | |
532 | ||
533 | parent_name = of_clk_get_parent_name(np, 0); | |
534 | if (!parent_name) | |
535 | return; | |
536 | ||
537 | reg = clkgen_get_register_base(np); | |
538 | if (!reg) | |
539 | return; | |
540 | ||
541 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
542 | if (!clk_data) | |
543 | return; | |
544 | ||
545 | clk_data->clk_num = num_pll_outputs; | |
546 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
547 | GFP_KERNEL); | |
548 | ||
549 | if (!clk_data->clks) | |
550 | goto err; | |
551 | ||
552 | if (of_property_read_string_index(np, "clock-output-names", | |
553 | 0, &clk_name)) | |
554 | goto err; | |
555 | ||
556 | /* | |
557 | * PLL0 HS (high speed) output | |
558 | */ | |
559 | clk_data->clks[0] = clkgen_pll_register(parent_name, | |
dc4febef GF |
560 | (struct clkgen_pll_data *) &st_pll1600c65_ax, |
561 | reg + CLKGENAx_PLL0_OFFSET, clk_name); | |
b9b8e614 GF |
562 | |
563 | if (IS_ERR(clk_data->clks[0])) | |
564 | goto err; | |
565 | ||
566 | if (of_property_read_string_index(np, "clock-output-names", | |
567 | 1, &clk_name)) | |
568 | goto err; | |
569 | ||
570 | /* | |
571 | * PLL0 LS (low speed) output, which is a fixed divide by 2 of the | |
572 | * high speed output. | |
573 | */ | |
574 | clk_data->clks[1] = clkgen_c65_lsdiv_register(__clk_get_name | |
575 | (clk_data->clks[0]), | |
576 | clk_name); | |
577 | ||
578 | if (IS_ERR(clk_data->clks[1])) | |
579 | goto err; | |
580 | ||
581 | if (of_property_read_string_index(np, "clock-output-names", | |
582 | 2, &clk_name)) | |
583 | goto err; | |
584 | ||
585 | /* | |
586 | * PLL1 output | |
587 | */ | |
588 | clk_data->clks[2] = clkgen_pll_register(parent_name, | |
dc4febef GF |
589 | (struct clkgen_pll_data *) &st_pll800c65_ax, |
590 | reg + CLKGENAx_PLL1_OFFSET, clk_name); | |
b9b8e614 GF |
591 | |
592 | if (IS_ERR(clk_data->clks[2])) | |
593 | goto err; | |
594 | ||
595 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
596 | return; | |
597 | ||
598 | err: | |
599 | kfree(clk_data->clks); | |
600 | kfree(clk_data); | |
601 | } | |
602 | CLK_OF_DECLARE(clkgena_c65_plls, | |
603 | "st,clkgena-plls-c65", clkgena_c65_pll_setup); | |
604 | ||
605 | static struct clk * __init clkgen_odf_register(const char *parent_name, | |
8e6dd77c | 606 | void __iomem *reg, |
b9b8e614 GF |
607 | struct clkgen_pll_data *pll_data, |
608 | int odf, | |
609 | spinlock_t *odf_lock, | |
610 | const char *odf_name) | |
611 | { | |
612 | struct clk *clk; | |
613 | unsigned long flags; | |
614 | struct clk_gate *gate; | |
615 | struct clk_divider *div; | |
616 | ||
617 | flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; | |
618 | ||
619 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | |
620 | if (!gate) | |
621 | return ERR_PTR(-ENOMEM); | |
622 | ||
623 | gate->flags = CLK_GATE_SET_TO_DISABLE; | |
624 | gate->reg = reg + pll_data->odf_gate[odf].offset; | |
625 | gate->bit_idx = pll_data->odf_gate[odf].shift; | |
626 | gate->lock = odf_lock; | |
627 | ||
628 | div = kzalloc(sizeof(*div), GFP_KERNEL); | |
72b1c2c3 VI |
629 | if (!div) { |
630 | kfree(gate); | |
b9b8e614 | 631 | return ERR_PTR(-ENOMEM); |
72b1c2c3 | 632 | } |
b9b8e614 GF |
633 | |
634 | div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; | |
635 | div->reg = reg + pll_data->odf[odf].offset; | |
636 | div->shift = pll_data->odf[odf].shift; | |
637 | div->width = fls(pll_data->odf[odf].mask); | |
638 | div->lock = odf_lock; | |
639 | ||
640 | clk = clk_register_composite(NULL, odf_name, &parent_name, 1, | |
641 | NULL, NULL, | |
642 | &div->hw, &clk_divider_ops, | |
643 | &gate->hw, &clk_gate_ops, | |
644 | flags); | |
645 | if (IS_ERR(clk)) | |
646 | return clk; | |
647 | ||
648 | pr_debug("%s: parent %s rate %lu\n", | |
649 | __clk_get_name(clk), | |
650 | __clk_get_name(clk_get_parent(clk)), | |
651 | clk_get_rate(clk)); | |
652 | return clk; | |
653 | } | |
654 | ||
f375573c | 655 | static const struct of_device_id c32_pll_of_match[] = { |
b9b8e614 GF |
656 | { |
657 | .compatible = "st,plls-c32-a1x-0", | |
658 | .data = &st_pll3200c32_a1x_0, | |
659 | }, | |
660 | { | |
661 | .compatible = "st,plls-c32-a1x-1", | |
662 | .data = &st_pll3200c32_a1x_1, | |
663 | }, | |
ec8d27b4 GF |
664 | { |
665 | .compatible = "st,stih415-plls-c32-a9", | |
666 | .data = &st_pll3200c32_a9_415, | |
667 | }, | |
668 | { | |
669 | .compatible = "st,stih415-plls-c32-ddr", | |
670 | .data = &st_pll3200c32_ddr_415, | |
671 | }, | |
672 | { | |
673 | .compatible = "st,stih416-plls-c32-a9", | |
674 | .data = &st_pll3200c32_a9_416, | |
675 | }, | |
676 | { | |
677 | .compatible = "st,stih416-plls-c32-ddr", | |
678 | .data = &st_pll3200c32_ddr_416, | |
679 | }, | |
eee8f783 GF |
680 | { |
681 | .compatible = "st,stih407-plls-c32-a0", | |
682 | .data = &st_pll3200c32_407_a0, | |
683 | }, | |
51306d56 | 684 | { |
d34e210e GF |
685 | .compatible = "st,plls-c32-cx_0", |
686 | .data = &st_pll3200c32_cx_0, | |
51306d56 GF |
687 | }, |
688 | { | |
d34e210e GF |
689 | .compatible = "st,plls-c32-cx_1", |
690 | .data = &st_pll3200c32_cx_1, | |
51306d56 | 691 | }, |
aaa65d77 GF |
692 | { |
693 | .compatible = "st,stih407-plls-c32-a9", | |
694 | .data = &st_pll3200c32_407_a9, | |
695 | }, | |
b9b8e614 GF |
696 | {} |
697 | }; | |
698 | ||
699 | static void __init clkgen_c32_pll_setup(struct device_node *np) | |
700 | { | |
701 | const struct of_device_id *match; | |
702 | struct clk *clk; | |
703 | const char *parent_name, *pll_name; | |
704 | void __iomem *pll_base; | |
705 | int num_odfs, odf; | |
706 | struct clk_onecell_data *clk_data; | |
707 | struct clkgen_pll_data *data; | |
708 | ||
709 | match = of_match_node(c32_pll_of_match, np); | |
710 | if (!match) { | |
711 | pr_err("%s: No matching data\n", __func__); | |
712 | return; | |
713 | } | |
714 | ||
715 | data = (struct clkgen_pll_data *) match->data; | |
716 | ||
717 | parent_name = of_clk_get_parent_name(np, 0); | |
718 | if (!parent_name) | |
719 | return; | |
720 | ||
721 | pll_base = clkgen_get_register_base(np); | |
722 | if (!pll_base) | |
723 | return; | |
724 | ||
725 | clk = clkgen_pll_register(parent_name, data, pll_base, np->name); | |
726 | if (IS_ERR(clk)) | |
727 | return; | |
728 | ||
729 | pll_name = __clk_get_name(clk); | |
730 | ||
731 | num_odfs = data->num_odfs; | |
732 | ||
733 | clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); | |
734 | if (!clk_data) | |
735 | return; | |
736 | ||
737 | clk_data->clk_num = num_odfs; | |
738 | clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), | |
739 | GFP_KERNEL); | |
740 | ||
741 | if (!clk_data->clks) | |
742 | goto err; | |
743 | ||
744 | for (odf = 0; odf < num_odfs; odf++) { | |
745 | struct clk *clk; | |
746 | const char *clk_name; | |
747 | ||
748 | if (of_property_read_string_index(np, "clock-output-names", | |
749 | odf, &clk_name)) | |
750 | return; | |
751 | ||
752 | clk = clkgen_odf_register(pll_name, pll_base, data, | |
753 | odf, &clkgena_c32_odf_lock, clk_name); | |
754 | if (IS_ERR(clk)) | |
755 | goto err; | |
756 | ||
757 | clk_data->clks[odf] = clk; | |
758 | } | |
759 | ||
760 | of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | |
761 | return; | |
762 | ||
763 | err: | |
764 | kfree(pll_name); | |
765 | kfree(clk_data->clks); | |
766 | kfree(clk_data); | |
767 | } | |
768 | CLK_OF_DECLARE(clkgen_c32_pll, "st,clkgen-plls-c32", clkgen_c32_pll_setup); | |
ec8d27b4 | 769 | |
f375573c | 770 | static const struct of_device_id c32_gpu_pll_of_match[] = { |
ec8d27b4 GF |
771 | { |
772 | .compatible = "st,stih415-gpu-pll-c32", | |
773 | .data = &st_pll1200c32_gpu_415, | |
774 | }, | |
775 | { | |
776 | .compatible = "st,stih416-gpu-pll-c32", | |
777 | .data = &st_pll1200c32_gpu_416, | |
778 | }, | |
70040b35 | 779 | {} |
ec8d27b4 GF |
780 | }; |
781 | ||
782 | static void __init clkgengpu_c32_pll_setup(struct device_node *np) | |
783 | { | |
784 | const struct of_device_id *match; | |
785 | struct clk *clk; | |
786 | const char *parent_name; | |
787 | void __iomem *reg; | |
788 | const char *clk_name; | |
789 | struct clkgen_pll_data *data; | |
790 | ||
791 | match = of_match_node(c32_gpu_pll_of_match, np); | |
792 | if (!match) { | |
793 | pr_err("%s: No matching data\n", __func__); | |
794 | return; | |
795 | } | |
796 | ||
797 | data = (struct clkgen_pll_data *)match->data; | |
798 | ||
799 | parent_name = of_clk_get_parent_name(np, 0); | |
800 | if (!parent_name) | |
801 | return; | |
802 | ||
803 | reg = clkgen_get_register_base(np); | |
804 | if (!reg) | |
805 | return; | |
806 | ||
807 | if (of_property_read_string_index(np, "clock-output-names", | |
808 | 0, &clk_name)) | |
809 | return; | |
810 | ||
811 | /* | |
812 | * PLL 1200MHz output | |
813 | */ | |
814 | clk = clkgen_pll_register(parent_name, data, reg, clk_name); | |
815 | ||
816 | if (!IS_ERR(clk)) | |
817 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | |
818 | ||
819 | return; | |
820 | } | |
821 | CLK_OF_DECLARE(clkgengpu_c32_pll, | |
822 | "st,clkgengpu-pll-c32", clkgengpu_c32_pll_setup); |