diff options
Diffstat (limited to 'drivers/clk/meson/meson8b.c')
-rw-r--r-- | drivers/clk/meson/meson8b.c | 705 |
1 files changed, 452 insertions, 253 deletions
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3ffea80c1308..cc2992493e0b 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c | |||
@@ -23,14 +23,16 @@ | |||
23 | 23 | ||
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/clk-provider.h> | 25 | #include <linux/clk-provider.h> |
26 | #include <linux/init.h> | ||
26 | #include <linux/of_address.h> | 27 | #include <linux/of_address.h> |
27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
28 | #include <linux/reset-controller.h> | 29 | #include <linux/reset-controller.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | #include <linux/init.h> | 31 | #include <linux/regmap.h> |
31 | 32 | ||
32 | #include "clkc.h" | 33 | #include "clkc.h" |
33 | #include "meson8b.h" | 34 | #include "meson8b.h" |
35 | #include "clk-regmap.h" | ||
34 | 36 | ||
35 | static DEFINE_SPINLOCK(meson_clk_lock); | 37 | static DEFINE_SPINLOCK(meson_clk_lock); |
36 | 38 | ||
@@ -97,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = { | |||
97 | { /* sentinel */ }, | 99 | { /* sentinel */ }, |
98 | }; | 100 | }; |
99 | 101 | ||
100 | static const struct clk_div_table cpu_div_table[] = { | ||
101 | { .val = 1, .div = 1 }, | ||
102 | { .val = 2, .div = 2 }, | ||
103 | { .val = 3, .div = 3 }, | ||
104 | { .val = 2, .div = 4 }, | ||
105 | { .val = 3, .div = 6 }, | ||
106 | { .val = 4, .div = 8 }, | ||
107 | { .val = 5, .div = 10 }, | ||
108 | { .val = 6, .div = 12 }, | ||
109 | { .val = 7, .div = 14 }, | ||
110 | { .val = 8, .div = 16 }, | ||
111 | { /* sentinel */ }, | ||
112 | }; | ||
113 | |||
114 | static struct clk_fixed_rate meson8b_xtal = { | 102 | static struct clk_fixed_rate meson8b_xtal = { |
115 | .fixed_rate = 24000000, | 103 | .fixed_rate = 24000000, |
116 | .hw.init = &(struct clk_init_data){ | 104 | .hw.init = &(struct clk_init_data){ |
@@ -120,23 +108,39 @@ static struct clk_fixed_rate meson8b_xtal = { | |||
120 | }, | 108 | }, |
121 | }; | 109 | }; |
122 | 110 | ||
123 | static struct meson_clk_pll meson8b_fixed_pll = { | 111 | static struct clk_regmap meson8b_fixed_pll = { |
124 | .m = { | 112 | .data = &(struct meson_clk_pll_data){ |
125 | .reg_off = HHI_MPLL_CNTL, | 113 | .m = { |
126 | .shift = 0, | 114 | .reg_off = HHI_MPLL_CNTL, |
127 | .width = 9, | 115 | .shift = 0, |
128 | }, | 116 | .width = 9, |
129 | .n = { | 117 | }, |
130 | .reg_off = HHI_MPLL_CNTL, | 118 | .n = { |
131 | .shift = 9, | 119 | .reg_off = HHI_MPLL_CNTL, |
132 | .width = 5, | 120 | .shift = 9, |
133 | }, | 121 | .width = 5, |
134 | .od = { | 122 | }, |
135 | .reg_off = HHI_MPLL_CNTL, | 123 | .od = { |
136 | .shift = 16, | 124 | .reg_off = HHI_MPLL_CNTL, |
137 | .width = 2, | 125 | .shift = 16, |
126 | .width = 2, | ||
127 | }, | ||
128 | .frac = { | ||
129 | .reg_off = HHI_MPLL_CNTL2, | ||
130 | .shift = 0, | ||
131 | .width = 12, | ||
132 | }, | ||
133 | .l = { | ||
134 | .reg_off = HHI_MPLL_CNTL, | ||
135 | .shift = 31, | ||
136 | .width = 1, | ||
137 | }, | ||
138 | .rst = { | ||
139 | .reg_off = HHI_MPLL_CNTL, | ||
140 | .shift = 29, | ||
141 | .width = 1, | ||
142 | }, | ||
138 | }, | 143 | }, |
139 | .lock = &meson_clk_lock, | ||
140 | .hw.init = &(struct clk_init_data){ | 144 | .hw.init = &(struct clk_init_data){ |
141 | .name = "fixed_pll", | 145 | .name = "fixed_pll", |
142 | .ops = &meson_clk_pll_ro_ops, | 146 | .ops = &meson_clk_pll_ro_ops, |
@@ -146,23 +150,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { | |||
146 | }, | 150 | }, |
147 | }; | 151 | }; |
148 | 152 | ||
149 | static struct meson_clk_pll meson8b_vid_pll = { | 153 | static struct clk_regmap meson8b_vid_pll = { |
150 | .m = { | 154 | .data = &(struct meson_clk_pll_data){ |
151 | .reg_off = HHI_VID_PLL_CNTL, | 155 | .m = { |
152 | .shift = 0, | 156 | .reg_off = HHI_VID_PLL_CNTL, |
153 | .width = 9, | 157 | .shift = 0, |
158 | .width = 9, | ||
159 | }, | ||
160 | .n = { | ||
161 | .reg_off = HHI_VID_PLL_CNTL, | ||
162 | .shift = 9, | ||
163 | .width = 5, | ||
164 | }, | ||
165 | .od = { | ||
166 | .reg_off = HHI_VID_PLL_CNTL, | ||
167 | .shift = 16, | ||
168 | .width = 2, | ||
169 | }, | ||
170 | .l = { | ||
171 | .reg_off = HHI_VID_PLL_CNTL, | ||
172 | .shift = 31, | ||
173 | .width = 1, | ||
174 | }, | ||
175 | .rst = { | ||
176 | .reg_off = HHI_VID_PLL_CNTL, | ||
177 | .shift = 29, | ||
178 | .width = 1, | ||
179 | }, | ||
154 | }, | 180 | }, |
155 | .n = { | ||
156 | .reg_off = HHI_VID_PLL_CNTL, | ||
157 | .shift = 9, | ||
158 | .width = 5, | ||
159 | }, | ||
160 | .od = { | ||
161 | .reg_off = HHI_VID_PLL_CNTL, | ||
162 | .shift = 16, | ||
163 | .width = 2, | ||
164 | }, | ||
165 | .lock = &meson_clk_lock, | ||
166 | .hw.init = &(struct clk_init_data){ | 181 | .hw.init = &(struct clk_init_data){ |
167 | .name = "vid_pll", | 182 | .name = "vid_pll", |
168 | .ops = &meson_clk_pll_ro_ops, | 183 | .ops = &meson_clk_pll_ro_ops, |
@@ -172,213 +187,317 @@ static struct meson_clk_pll meson8b_vid_pll = { | |||
172 | }, | 187 | }, |
173 | }; | 188 | }; |
174 | 189 | ||
175 | static struct meson_clk_pll meson8b_sys_pll = { | 190 | static struct clk_regmap meson8b_sys_pll = { |
176 | .m = { | 191 | .data = &(struct meson_clk_pll_data){ |
177 | .reg_off = HHI_SYS_PLL_CNTL, | 192 | .m = { |
178 | .shift = 0, | 193 | .reg_off = HHI_SYS_PLL_CNTL, |
179 | .width = 9, | 194 | .shift = 0, |
180 | }, | 195 | .width = 9, |
181 | .n = { | 196 | }, |
182 | .reg_off = HHI_SYS_PLL_CNTL, | 197 | .n = { |
183 | .shift = 9, | 198 | .reg_off = HHI_SYS_PLL_CNTL, |
184 | .width = 5, | 199 | .shift = 9, |
200 | .width = 5, | ||
201 | }, | ||
202 | .od = { | ||
203 | .reg_off = HHI_SYS_PLL_CNTL, | ||
204 | .shift = 16, | ||
205 | .width = 2, | ||
206 | }, | ||
207 | .l = { | ||
208 | .reg_off = HHI_SYS_PLL_CNTL, | ||
209 | .shift = 31, | ||
210 | .width = 1, | ||
211 | }, | ||
212 | .rst = { | ||
213 | .reg_off = HHI_SYS_PLL_CNTL, | ||
214 | .shift = 29, | ||
215 | .width = 1, | ||
216 | }, | ||
217 | .table = sys_pll_rate_table, | ||
185 | }, | 218 | }, |
186 | .od = { | ||
187 | .reg_off = HHI_SYS_PLL_CNTL, | ||
188 | .shift = 16, | ||
189 | .width = 2, | ||
190 | }, | ||
191 | .rate_table = sys_pll_rate_table, | ||
192 | .rate_count = ARRAY_SIZE(sys_pll_rate_table), | ||
193 | .lock = &meson_clk_lock, | ||
194 | .hw.init = &(struct clk_init_data){ | 219 | .hw.init = &(struct clk_init_data){ |
195 | .name = "sys_pll", | 220 | .name = "sys_pll", |
196 | .ops = &meson_clk_pll_ops, | 221 | .ops = &meson_clk_pll_ro_ops, |
197 | .parent_names = (const char *[]){ "xtal" }, | 222 | .parent_names = (const char *[]){ "xtal" }, |
198 | .num_parents = 1, | 223 | .num_parents = 1, |
199 | .flags = CLK_GET_RATE_NOCACHE, | 224 | .flags = CLK_GET_RATE_NOCACHE, |
200 | }, | 225 | }, |
201 | }; | 226 | }; |
202 | 227 | ||
203 | static struct clk_fixed_factor meson8b_fclk_div2 = { | 228 | static struct clk_fixed_factor meson8b_fclk_div2_div = { |
204 | .mult = 1, | 229 | .mult = 1, |
205 | .div = 2, | 230 | .div = 2, |
206 | .hw.init = &(struct clk_init_data){ | 231 | .hw.init = &(struct clk_init_data){ |
207 | .name = "fclk_div2", | 232 | .name = "fclk_div2_div", |
208 | .ops = &clk_fixed_factor_ops, | 233 | .ops = &clk_fixed_factor_ops, |
209 | .parent_names = (const char *[]){ "fixed_pll" }, | 234 | .parent_names = (const char *[]){ "fixed_pll" }, |
210 | .num_parents = 1, | 235 | .num_parents = 1, |
211 | }, | 236 | }, |
212 | }; | 237 | }; |
213 | 238 | ||
214 | static struct clk_fixed_factor meson8b_fclk_div3 = { | 239 | static struct clk_regmap meson8b_fclk_div2 = { |
240 | .data = &(struct clk_regmap_gate_data){ | ||
241 | .offset = HHI_MPLL_CNTL6, | ||
242 | .bit_idx = 27, | ||
243 | }, | ||
244 | .hw.init = &(struct clk_init_data){ | ||
245 | .name = "fclk_div2", | ||
246 | .ops = &clk_regmap_gate_ops, | ||
247 | .parent_names = (const char *[]){ "fclk_div2_div" }, | ||
248 | .num_parents = 1, | ||
249 | }, | ||
250 | }; | ||
251 | |||
252 | static struct clk_fixed_factor meson8b_fclk_div3_div = { | ||
215 | .mult = 1, | 253 | .mult = 1, |
216 | .div = 3, | 254 | .div = 3, |
217 | .hw.init = &(struct clk_init_data){ | 255 | .hw.init = &(struct clk_init_data){ |
218 | .name = "fclk_div3", | 256 | .name = "fclk_div_div3", |
219 | .ops = &clk_fixed_factor_ops, | 257 | .ops = &clk_fixed_factor_ops, |
220 | .parent_names = (const char *[]){ "fixed_pll" }, | 258 | .parent_names = (const char *[]){ "fixed_pll" }, |
221 | .num_parents = 1, | 259 | .num_parents = 1, |
222 | }, | 260 | }, |
223 | }; | 261 | }; |
224 | 262 | ||
225 | static struct clk_fixed_factor meson8b_fclk_div4 = { | 263 | static struct clk_regmap meson8b_fclk_div3 = { |
264 | .data = &(struct clk_regmap_gate_data){ | ||
265 | .offset = HHI_MPLL_CNTL6, | ||
266 | .bit_idx = 28, | ||
267 | }, | ||
268 | .hw.init = &(struct clk_init_data){ | ||
269 | .name = "fclk_div3", | ||
270 | .ops = &clk_regmap_gate_ops, | ||
271 | .parent_names = (const char *[]){ "fclk_div3_div" }, | ||
272 | .num_parents = 1, | ||
273 | }, | ||
274 | }; | ||
275 | |||
276 | static struct clk_fixed_factor meson8b_fclk_div4_div = { | ||
226 | .mult = 1, | 277 | .mult = 1, |
227 | .div = 4, | 278 | .div = 4, |
228 | .hw.init = &(struct clk_init_data){ | 279 | .hw.init = &(struct clk_init_data){ |
229 | .name = "fclk_div4", | 280 | .name = "fclk_div4_div", |
230 | .ops = &clk_fixed_factor_ops, | 281 | .ops = &clk_fixed_factor_ops, |
231 | .parent_names = (const char *[]){ "fixed_pll" }, | 282 | .parent_names = (const char *[]){ "fixed_pll" }, |
232 | .num_parents = 1, | 283 | .num_parents = 1, |
233 | }, | 284 | }, |
234 | }; | 285 | }; |
235 | 286 | ||
236 | static struct clk_fixed_factor meson8b_fclk_div5 = { | 287 | static struct clk_regmap meson8b_fclk_div4 = { |
288 | .data = &(struct clk_regmap_gate_data){ | ||
289 | .offset = HHI_MPLL_CNTL6, | ||
290 | .bit_idx = 29, | ||
291 | }, | ||
292 | .hw.init = &(struct clk_init_data){ | ||
293 | .name = "fclk_div4", | ||
294 | .ops = &clk_regmap_gate_ops, | ||
295 | .parent_names = (const char *[]){ "fclk_div4_div" }, | ||
296 | .num_parents = 1, | ||
297 | }, | ||
298 | }; | ||
299 | |||
300 | static struct clk_fixed_factor meson8b_fclk_div5_div = { | ||
237 | .mult = 1, | 301 | .mult = 1, |
238 | .div = 5, | 302 | .div = 5, |
239 | .hw.init = &(struct clk_init_data){ | 303 | .hw.init = &(struct clk_init_data){ |
240 | .name = "fclk_div5", | 304 | .name = "fclk_div5_div", |
241 | .ops = &clk_fixed_factor_ops, | 305 | .ops = &clk_fixed_factor_ops, |
242 | .parent_names = (const char *[]){ "fixed_pll" }, | 306 | .parent_names = (const char *[]){ "fixed_pll" }, |
243 | .num_parents = 1, | 307 | .num_parents = 1, |
244 | }, | 308 | }, |
245 | }; | 309 | }; |
246 | 310 | ||
247 | static struct clk_fixed_factor meson8b_fclk_div7 = { | 311 | static struct clk_regmap meson8b_fclk_div5 = { |
312 | .data = &(struct clk_regmap_gate_data){ | ||
313 | .offset = HHI_MPLL_CNTL6, | ||
314 | .bit_idx = 30, | ||
315 | }, | ||
316 | .hw.init = &(struct clk_init_data){ | ||
317 | .name = "fclk_div5", | ||
318 | .ops = &clk_regmap_gate_ops, | ||
319 | .parent_names = (const char *[]){ "fclk_div5_div" }, | ||
320 | .num_parents = 1, | ||
321 | }, | ||
322 | }; | ||
323 | |||
324 | static struct clk_fixed_factor meson8b_fclk_div7_div = { | ||
248 | .mult = 1, | 325 | .mult = 1, |
249 | .div = 7, | 326 | .div = 7, |
250 | .hw.init = &(struct clk_init_data){ | 327 | .hw.init = &(struct clk_init_data){ |
251 | .name = "fclk_div7", | 328 | .name = "fclk_div7_div", |
252 | .ops = &clk_fixed_factor_ops, | 329 | .ops = &clk_fixed_factor_ops, |
253 | .parent_names = (const char *[]){ "fixed_pll" }, | 330 | .parent_names = (const char *[]){ "fixed_pll" }, |
254 | .num_parents = 1, | 331 | .num_parents = 1, |
255 | }, | 332 | }, |
256 | }; | 333 | }; |
257 | 334 | ||
258 | static struct meson_clk_mpll meson8b_mpll0 = { | 335 | static struct clk_regmap meson8b_fclk_div7 = { |
259 | .sdm = { | 336 | .data = &(struct clk_regmap_gate_data){ |
260 | .reg_off = HHI_MPLL_CNTL7, | 337 | .offset = HHI_MPLL_CNTL6, |
261 | .shift = 0, | 338 | .bit_idx = 31, |
262 | .width = 14, | ||
263 | }, | 339 | }, |
264 | .sdm_en = { | 340 | .hw.init = &(struct clk_init_data){ |
265 | .reg_off = HHI_MPLL_CNTL7, | 341 | .name = "fclk_div7", |
266 | .shift = 15, | 342 | .ops = &clk_regmap_gate_ops, |
267 | .width = 1, | 343 | .parent_names = (const char *[]){ "fclk_div7_div" }, |
344 | .num_parents = 1, | ||
268 | }, | 345 | }, |
269 | .n2 = { | 346 | }; |
270 | .reg_off = HHI_MPLL_CNTL7, | 347 | |
271 | .shift = 16, | 348 | static struct clk_regmap meson8b_mpll_prediv = { |
272 | .width = 9, | 349 | .data = &(struct clk_regmap_div_data){ |
350 | .offset = HHI_MPLL_CNTL5, | ||
351 | .shift = 12, | ||
352 | .width = 1, | ||
273 | }, | 353 | }, |
274 | .en = { | 354 | .hw.init = &(struct clk_init_data){ |
275 | .reg_off = HHI_MPLL_CNTL7, | 355 | .name = "mpll_prediv", |
276 | .shift = 14, | 356 | .ops = &clk_regmap_divider_ro_ops, |
277 | .width = 1, | 357 | .parent_names = (const char *[]){ "fixed_pll" }, |
358 | .num_parents = 1, | ||
278 | }, | 359 | }, |
279 | .ssen = { | 360 | }; |
280 | .reg_off = HHI_MPLL_CNTL, | 361 | |
281 | .shift = 25, | 362 | static struct clk_regmap meson8b_mpll0_div = { |
282 | .width = 1, | 363 | .data = &(struct meson_clk_mpll_data){ |
364 | .sdm = { | ||
365 | .reg_off = HHI_MPLL_CNTL7, | ||
366 | .shift = 0, | ||
367 | .width = 14, | ||
368 | }, | ||
369 | .sdm_en = { | ||
370 | .reg_off = HHI_MPLL_CNTL7, | ||
371 | .shift = 15, | ||
372 | .width = 1, | ||
373 | }, | ||
374 | .n2 = { | ||
375 | .reg_off = HHI_MPLL_CNTL7, | ||
376 | .shift = 16, | ||
377 | .width = 9, | ||
378 | }, | ||
379 | .ssen = { | ||
380 | .reg_off = HHI_MPLL_CNTL, | ||
381 | .shift = 25, | ||
382 | .width = 1, | ||
383 | }, | ||
384 | .lock = &meson_clk_lock, | ||
283 | }, | 385 | }, |
284 | .lock = &meson_clk_lock, | ||
285 | .hw.init = &(struct clk_init_data){ | 386 | .hw.init = &(struct clk_init_data){ |
286 | .name = "mpll0", | 387 | .name = "mpll0_div", |
287 | .ops = &meson_clk_mpll_ops, | 388 | .ops = &meson_clk_mpll_ops, |
288 | .parent_names = (const char *[]){ "fixed_pll" }, | 389 | .parent_names = (const char *[]){ "mpll_prediv" }, |
289 | .num_parents = 1, | 390 | .num_parents = 1, |
290 | }, | 391 | }, |
291 | }; | 392 | }; |
292 | 393 | ||
293 | static struct meson_clk_mpll meson8b_mpll1 = { | 394 | static struct clk_regmap meson8b_mpll0 = { |
294 | .sdm = { | 395 | .data = &(struct clk_regmap_gate_data){ |
295 | .reg_off = HHI_MPLL_CNTL8, | 396 | .offset = HHI_MPLL_CNTL7, |
296 | .shift = 0, | 397 | .bit_idx = 14, |
297 | .width = 14, | ||
298 | }, | 398 | }, |
299 | .sdm_en = { | 399 | .hw.init = &(struct clk_init_data){ |
300 | .reg_off = HHI_MPLL_CNTL8, | 400 | .name = "mpll0", |
301 | .shift = 15, | 401 | .ops = &clk_regmap_gate_ops, |
302 | .width = 1, | 402 | .parent_names = (const char *[]){ "mpll0_div" }, |
303 | }, | 403 | .num_parents = 1, |
304 | .n2 = { | 404 | .flags = CLK_SET_RATE_PARENT, |
305 | .reg_off = HHI_MPLL_CNTL8, | ||
306 | .shift = 16, | ||
307 | .width = 9, | ||
308 | }, | 405 | }, |
309 | .en = { | 406 | }; |
310 | .reg_off = HHI_MPLL_CNTL8, | 407 | |
311 | .shift = 14, | 408 | static struct clk_regmap meson8b_mpll1_div = { |
312 | .width = 1, | 409 | .data = &(struct meson_clk_mpll_data){ |
410 | .sdm = { | ||
411 | .reg_off = HHI_MPLL_CNTL8, | ||
412 | .shift = 0, | ||
413 | .width = 14, | ||
414 | }, | ||
415 | .sdm_en = { | ||
416 | .reg_off = HHI_MPLL_CNTL8, | ||
417 | .shift = 15, | ||
418 | .width = 1, | ||
419 | }, | ||
420 | .n2 = { | ||
421 | .reg_off = HHI_MPLL_CNTL8, | ||
422 | .shift = 16, | ||
423 | .width = 9, | ||
424 | }, | ||
425 | .lock = &meson_clk_lock, | ||
313 | }, | 426 | }, |
314 | .lock = &meson_clk_lock, | ||
315 | .hw.init = &(struct clk_init_data){ | 427 | .hw.init = &(struct clk_init_data){ |
316 | .name = "mpll1", | 428 | .name = "mpll1_div", |
317 | .ops = &meson_clk_mpll_ops, | 429 | .ops = &meson_clk_mpll_ops, |
318 | .parent_names = (const char *[]){ "fixed_pll" }, | 430 | .parent_names = (const char *[]){ "mpll_prediv" }, |
319 | .num_parents = 1, | 431 | .num_parents = 1, |
320 | }, | 432 | }, |
321 | }; | 433 | }; |
322 | 434 | ||
323 | static struct meson_clk_mpll meson8b_mpll2 = { | 435 | static struct clk_regmap meson8b_mpll1 = { |
324 | .sdm = { | 436 | .data = &(struct clk_regmap_gate_data){ |
325 | .reg_off = HHI_MPLL_CNTL9, | 437 | .offset = HHI_MPLL_CNTL8, |
326 | .shift = 0, | 438 | .bit_idx = 14, |
327 | .width = 14, | ||
328 | }, | ||
329 | .sdm_en = { | ||
330 | .reg_off = HHI_MPLL_CNTL9, | ||
331 | .shift = 15, | ||
332 | .width = 1, | ||
333 | }, | 439 | }, |
334 | .n2 = { | 440 | .hw.init = &(struct clk_init_data){ |
335 | .reg_off = HHI_MPLL_CNTL9, | 441 | .name = "mpll1", |
336 | .shift = 16, | 442 | .ops = &clk_regmap_gate_ops, |
337 | .width = 9, | 443 | .parent_names = (const char *[]){ "mpll1_div" }, |
444 | .num_parents = 1, | ||
445 | .flags = CLK_SET_RATE_PARENT, | ||
338 | }, | 446 | }, |
339 | .en = { | 447 | }; |
340 | .reg_off = HHI_MPLL_CNTL9, | 448 | |
341 | .shift = 14, | 449 | static struct clk_regmap meson8b_mpll2_div = { |
342 | .width = 1, | 450 | .data = &(struct meson_clk_mpll_data){ |
451 | .sdm = { | ||
452 | .reg_off = HHI_MPLL_CNTL9, | ||
453 | .shift = 0, | ||
454 | .width = 14, | ||
455 | }, | ||
456 | .sdm_en = { | ||
457 | .reg_off = HHI_MPLL_CNTL9, | ||
458 | .shift = 15, | ||
459 | .width = 1, | ||
460 | }, | ||
461 | .n2 = { | ||
462 | .reg_off = HHI_MPLL_CNTL9, | ||
463 | .shift = 16, | ||
464 | .width = 9, | ||
465 | }, | ||
466 | .lock = &meson_clk_lock, | ||
343 | }, | 467 | }, |
344 | .lock = &meson_clk_lock, | ||
345 | .hw.init = &(struct clk_init_data){ | 468 | .hw.init = &(struct clk_init_data){ |
346 | .name = "mpll2", | 469 | .name = "mpll2_div", |
347 | .ops = &meson_clk_mpll_ops, | 470 | .ops = &meson_clk_mpll_ops, |
348 | .parent_names = (const char *[]){ "fixed_pll" }, | 471 | .parent_names = (const char *[]){ "mpll_prediv" }, |
349 | .num_parents = 1, | 472 | .num_parents = 1, |
350 | }, | 473 | }, |
351 | }; | 474 | }; |
352 | 475 | ||
353 | /* | 476 | static struct clk_regmap meson8b_mpll2 = { |
354 | * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL | 477 | .data = &(struct clk_regmap_gate_data){ |
355 | * post-dividers and should be modeled with their respective PLLs via the | 478 | .offset = HHI_MPLL_CNTL9, |
356 | * forthcoming coordinated clock rates feature | 479 | .bit_idx = 14, |
357 | */ | 480 | }, |
358 | static struct meson_clk_cpu meson8b_cpu_clk = { | ||
359 | .reg_off = HHI_SYS_CPU_CLK_CNTL1, | ||
360 | .div_table = cpu_div_table, | ||
361 | .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, | ||
362 | .hw.init = &(struct clk_init_data){ | 481 | .hw.init = &(struct clk_init_data){ |
363 | .name = "cpu_clk", | 482 | .name = "mpll2", |
364 | .ops = &meson_clk_cpu_ops, | 483 | .ops = &clk_regmap_gate_ops, |
365 | .parent_names = (const char *[]){ "sys_pll" }, | 484 | .parent_names = (const char *[]){ "mpll2_div" }, |
366 | .num_parents = 1, | 485 | .num_parents = 1, |
486 | .flags = CLK_SET_RATE_PARENT, | ||
367 | }, | 487 | }, |
368 | }; | 488 | }; |
369 | 489 | ||
370 | static u32 mux_table_clk81[] = { 6, 5, 7 }; | 490 | static u32 mux_table_clk81[] = { 6, 5, 7 }; |
371 | 491 | static struct clk_regmap meson8b_mpeg_clk_sel = { | |
372 | struct clk_mux meson8b_mpeg_clk_sel = { | 492 | .data = &(struct clk_regmap_mux_data){ |
373 | .reg = (void *)HHI_MPEG_CLK_CNTL, | 493 | .offset = HHI_MPEG_CLK_CNTL, |
374 | .mask = 0x7, | 494 | .mask = 0x7, |
375 | .shift = 12, | 495 | .shift = 12, |
376 | .flags = CLK_MUX_READ_ONLY, | 496 | .table = mux_table_clk81, |
377 | .table = mux_table_clk81, | 497 | }, |
378 | .lock = &meson_clk_lock, | ||
379 | .hw.init = &(struct clk_init_data){ | 498 | .hw.init = &(struct clk_init_data){ |
380 | .name = "mpeg_clk_sel", | 499 | .name = "mpeg_clk_sel", |
381 | .ops = &clk_mux_ro_ops, | 500 | .ops = &clk_regmap_mux_ro_ops, |
382 | /* | 501 | /* |
383 | * FIXME bits 14:12 selects from 8 possible parents: | 502 | * FIXME bits 14:12 selects from 8 possible parents: |
384 | * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, | 503 | * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, |
@@ -387,34 +506,136 @@ struct clk_mux meson8b_mpeg_clk_sel = { | |||
387 | .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", | 506 | .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", |
388 | "fclk_div5" }, | 507 | "fclk_div5" }, |
389 | .num_parents = 3, | 508 | .num_parents = 3, |
390 | .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), | ||
391 | }, | 509 | }, |
392 | }; | 510 | }; |
393 | 511 | ||
394 | struct clk_divider meson8b_mpeg_clk_div = { | 512 | static struct clk_regmap meson8b_mpeg_clk_div = { |
395 | .reg = (void *)HHI_MPEG_CLK_CNTL, | 513 | .data = &(struct clk_regmap_div_data){ |
396 | .shift = 0, | 514 | .offset = HHI_MPEG_CLK_CNTL, |
397 | .width = 7, | 515 | .shift = 0, |
398 | .lock = &meson_clk_lock, | 516 | .width = 7, |
517 | }, | ||
399 | .hw.init = &(struct clk_init_data){ | 518 | .hw.init = &(struct clk_init_data){ |
400 | .name = "mpeg_clk_div", | 519 | .name = "mpeg_clk_div", |
401 | .ops = &clk_divider_ops, | 520 | .ops = &clk_regmap_divider_ro_ops, |
402 | .parent_names = (const char *[]){ "mpeg_clk_sel" }, | 521 | .parent_names = (const char *[]){ "mpeg_clk_sel" }, |
403 | .num_parents = 1, | 522 | .num_parents = 1, |
404 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), | ||
405 | }, | 523 | }, |
406 | }; | 524 | }; |
407 | 525 | ||
408 | struct clk_gate meson8b_clk81 = { | 526 | static struct clk_regmap meson8b_clk81 = { |
409 | .reg = (void *)HHI_MPEG_CLK_CNTL, | 527 | .data = &(struct clk_regmap_gate_data){ |
410 | .bit_idx = 7, | 528 | .offset = HHI_MPEG_CLK_CNTL, |
411 | .lock = &meson_clk_lock, | 529 | .bit_idx = 7, |
530 | }, | ||
412 | .hw.init = &(struct clk_init_data){ | 531 | .hw.init = &(struct clk_init_data){ |
413 | .name = "clk81", | 532 | .name = "clk81", |
414 | .ops = &clk_gate_ops, | 533 | .ops = &clk_regmap_gate_ops, |
415 | .parent_names = (const char *[]){ "mpeg_clk_div" }, | 534 | .parent_names = (const char *[]){ "mpeg_clk_div" }, |
416 | .num_parents = 1, | 535 | .num_parents = 1, |
417 | .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), | 536 | .flags = CLK_IS_CRITICAL, |
537 | }, | ||
538 | }; | ||
539 | |||
540 | static struct clk_regmap meson8b_cpu_in_sel = { | ||
541 | .data = &(struct clk_regmap_mux_data){ | ||
542 | .offset = HHI_SYS_CPU_CLK_CNTL0, | ||
543 | .mask = 0x1, | ||
544 | .shift = 0, | ||
545 | }, | ||
546 | .hw.init = &(struct clk_init_data){ | ||
547 | .name = "cpu_in_sel", | ||
548 | .ops = &clk_regmap_mux_ro_ops, | ||
549 | .parent_names = (const char *[]){ "xtal", "sys_pll" }, | ||
550 | .num_parents = 2, | ||
551 | .flags = (CLK_SET_RATE_PARENT | | ||
552 | CLK_SET_RATE_NO_REPARENT), | ||
553 | }, | ||
554 | }; | ||
555 | |||
556 | static struct clk_fixed_factor meson8b_cpu_div2 = { | ||
557 | .mult = 1, | ||
558 | .div = 2, | ||
559 | .hw.init = &(struct clk_init_data){ | ||
560 | .name = "cpu_div2", | ||
561 | .ops = &clk_fixed_factor_ops, | ||
562 | .parent_names = (const char *[]){ "cpu_in_sel" }, | ||
563 | .num_parents = 1, | ||
564 | .flags = CLK_SET_RATE_PARENT, | ||
565 | }, | ||
566 | }; | ||
567 | |||
568 | static struct clk_fixed_factor meson8b_cpu_div3 = { | ||
569 | .mult = 1, | ||
570 | .div = 3, | ||
571 | .hw.init = &(struct clk_init_data){ | ||
572 | .name = "cpu_div3", | ||
573 | .ops = &clk_fixed_factor_ops, | ||
574 | .parent_names = (const char *[]){ "cpu_in_sel" }, | ||
575 | .num_parents = 1, | ||
576 | .flags = CLK_SET_RATE_PARENT, | ||
577 | }, | ||
578 | }; | ||
579 | |||
580 | static const struct clk_div_table cpu_scale_table[] = { | ||
581 | { .val = 2, .div = 4 }, | ||
582 | { .val = 3, .div = 6 }, | ||
583 | { .val = 4, .div = 8 }, | ||
584 | { .val = 5, .div = 10 }, | ||
585 | { .val = 6, .div = 12 }, | ||
586 | { .val = 7, .div = 14 }, | ||
587 | { .val = 8, .div = 16 }, | ||
588 | { /* sentinel */ }, | ||
589 | }; | ||
590 | |||
591 | static struct clk_regmap meson8b_cpu_scale_div = { | ||
592 | .data = &(struct clk_regmap_div_data){ | ||
593 | .offset = HHI_SYS_CPU_CLK_CNTL1, | ||
594 | .shift = 20, | ||
595 | .width = 9, | ||
596 | .table = cpu_scale_table, | ||
597 | .flags = CLK_DIVIDER_ALLOW_ZERO, | ||
598 | }, | ||
599 | .hw.init = &(struct clk_init_data){ | ||
600 | .name = "cpu_scale_div", | ||
601 | .ops = &clk_regmap_divider_ro_ops, | ||
602 | .parent_names = (const char *[]){ "cpu_in_sel" }, | ||
603 | .num_parents = 1, | ||
604 | .flags = CLK_SET_RATE_PARENT, | ||
605 | }, | ||
606 | }; | ||
607 | |||
608 | static struct clk_regmap meson8b_cpu_scale_out_sel = { | ||
609 | .data = &(struct clk_regmap_mux_data){ | ||
610 | .offset = HHI_SYS_CPU_CLK_CNTL0, | ||
611 | .mask = 0x3, | ||
612 | .shift = 2, | ||
613 | }, | ||
614 | .hw.init = &(struct clk_init_data){ | ||
615 | .name = "cpu_scale_out_sel", | ||
616 | .ops = &clk_regmap_mux_ro_ops, | ||
617 | .parent_names = (const char *[]) { "cpu_in_sel", | ||
618 | "cpu_div2", | ||
619 | "cpu_div3", | ||
620 | "cpu_scale_div" }, | ||
621 | .num_parents = 4, | ||
622 | .flags = CLK_SET_RATE_PARENT, | ||
623 | }, | ||
624 | }; | ||
625 | |||
626 | static struct clk_regmap meson8b_cpu_clk = { | ||
627 | .data = &(struct clk_regmap_mux_data){ | ||
628 | .offset = HHI_SYS_CPU_CLK_CNTL0, | ||
629 | .mask = 0x1, | ||
630 | .shift = 7, | ||
631 | }, | ||
632 | .hw.init = &(struct clk_init_data){ | ||
633 | .name = "cpu_clk", | ||
634 | .ops = &clk_regmap_mux_ro_ops, | ||
635 | .parent_names = (const char *[]){ "xtal", "cpu_out_sel" }, | ||
636 | .num_parents = 2, | ||
637 | .flags = (CLK_SET_RATE_PARENT | | ||
638 | CLK_SET_RATE_NO_REPARENT), | ||
418 | }, | 639 | }, |
419 | }; | 640 | }; |
420 | 641 | ||
@@ -599,24 +820,26 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { | |||
599 | [CLKID_MPLL0] = &meson8b_mpll0.hw, | 820 | [CLKID_MPLL0] = &meson8b_mpll0.hw, |
600 | [CLKID_MPLL1] = &meson8b_mpll1.hw, | 821 | [CLKID_MPLL1] = &meson8b_mpll1.hw, |
601 | [CLKID_MPLL2] = &meson8b_mpll2.hw, | 822 | [CLKID_MPLL2] = &meson8b_mpll2.hw, |
823 | [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, | ||
824 | [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, | ||
825 | [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, | ||
826 | [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, | ||
827 | [CLKID_CPU_DIV2] = &meson8b_cpu_div2.hw, | ||
828 | [CLKID_CPU_DIV3] = &meson8b_cpu_div3.hw, | ||
829 | [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, | ||
830 | [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, | ||
831 | [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, | ||
832 | [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, | ||
833 | [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, | ||
834 | [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, | ||
835 | [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, | ||
836 | [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, | ||
602 | [CLK_NR_CLKS] = NULL, | 837 | [CLK_NR_CLKS] = NULL, |
603 | }, | 838 | }, |
604 | .num = CLK_NR_CLKS, | 839 | .num = CLK_NR_CLKS, |
605 | }; | 840 | }; |
606 | 841 | ||
607 | static struct meson_clk_pll *const meson8b_clk_plls[] = { | 842 | static struct clk_regmap *const meson8b_clk_regmaps[] = { |
608 | &meson8b_fixed_pll, | ||
609 | &meson8b_vid_pll, | ||
610 | &meson8b_sys_pll, | ||
611 | }; | ||
612 | |||
613 | static struct meson_clk_mpll *const meson8b_clk_mplls[] = { | ||
614 | &meson8b_mpll0, | ||
615 | &meson8b_mpll1, | ||
616 | &meson8b_mpll2, | ||
617 | }; | ||
618 | |||
619 | static struct clk_gate *const meson8b_clk_gates[] = { | ||
620 | &meson8b_clk81, | 843 | &meson8b_clk81, |
621 | &meson8b_ddr, | 844 | &meson8b_ddr, |
622 | &meson8b_dos, | 845 | &meson8b_dos, |
@@ -695,14 +918,27 @@ static struct clk_gate *const meson8b_clk_gates[] = { | |||
695 | &meson8b_ao_ahb_sram, | 918 | &meson8b_ao_ahb_sram, |
696 | &meson8b_ao_ahb_bus, | 919 | &meson8b_ao_ahb_bus, |
697 | &meson8b_ao_iface, | 920 | &meson8b_ao_iface, |
698 | }; | ||
699 | |||
700 | static struct clk_mux *const meson8b_clk_muxes[] = { | ||
701 | &meson8b_mpeg_clk_sel, | ||
702 | }; | ||
703 | |||
704 | static struct clk_divider *const meson8b_clk_dividers[] = { | ||
705 | &meson8b_mpeg_clk_div, | 921 | &meson8b_mpeg_clk_div, |
922 | &meson8b_mpeg_clk_sel, | ||
923 | &meson8b_mpll0, | ||
924 | &meson8b_mpll1, | ||
925 | &meson8b_mpll2, | ||
926 | &meson8b_mpll0_div, | ||
927 | &meson8b_mpll1_div, | ||
928 | &meson8b_mpll2_div, | ||
929 | &meson8b_fixed_pll, | ||
930 | &meson8b_vid_pll, | ||
931 | &meson8b_sys_pll, | ||
932 | &meson8b_cpu_in_sel, | ||
933 | &meson8b_cpu_scale_div, | ||
934 | &meson8b_cpu_scale_out_sel, | ||
935 | &meson8b_cpu_clk, | ||
936 | &meson8b_mpll_prediv, | ||
937 | &meson8b_fclk_div2, | ||
938 | &meson8b_fclk_div3, | ||
939 | &meson8b_fclk_div4, | ||
940 | &meson8b_fclk_div5, | ||
941 | &meson8b_fclk_div7, | ||
706 | }; | 942 | }; |
707 | 943 | ||
708 | static const struct meson8b_clk_reset_line { | 944 | static const struct meson8b_clk_reset_line { |
@@ -804,82 +1040,45 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { | |||
804 | .deassert = meson8b_clk_reset_deassert, | 1040 | .deassert = meson8b_clk_reset_deassert, |
805 | }; | 1041 | }; |
806 | 1042 | ||
1043 | static const struct regmap_config clkc_regmap_config = { | ||
1044 | .reg_bits = 32, | ||
1045 | .val_bits = 32, | ||
1046 | .reg_stride = 4, | ||
1047 | }; | ||
1048 | |||
807 | static int meson8b_clkc_probe(struct platform_device *pdev) | 1049 | static int meson8b_clkc_probe(struct platform_device *pdev) |
808 | { | 1050 | { |
809 | int ret, clkid, i; | 1051 | int ret, i; |
810 | struct clk_hw *parent_hw; | ||
811 | struct clk *parent_clk; | ||
812 | struct device *dev = &pdev->dev; | 1052 | struct device *dev = &pdev->dev; |
1053 | struct regmap *map; | ||
813 | 1054 | ||
814 | if (!clk_base) | 1055 | if (!clk_base) |
815 | return -ENXIO; | 1056 | return -ENXIO; |
816 | 1057 | ||
817 | /* Populate base address for PLLs */ | 1058 | map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); |
818 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) | 1059 | if (IS_ERR(map)) |
819 | meson8b_clk_plls[i]->base = clk_base; | 1060 | return PTR_ERR(map); |
820 | |||
821 | /* Populate base address for MPLLs */ | ||
822 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++) | ||
823 | meson8b_clk_mplls[i]->base = clk_base; | ||
824 | |||
825 | /* Populate the base address for CPU clk */ | ||
826 | meson8b_cpu_clk.base = clk_base; | ||
827 | |||
828 | /* Populate base address for gates */ | ||
829 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) | ||
830 | meson8b_clk_gates[i]->reg = clk_base + | ||
831 | (u32)meson8b_clk_gates[i]->reg; | ||
832 | |||
833 | /* Populate base address for muxes */ | ||
834 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++) | ||
835 | meson8b_clk_muxes[i]->reg = clk_base + | ||
836 | (u32)meson8b_clk_muxes[i]->reg; | ||
837 | 1061 | ||
838 | /* Populate base address for dividers */ | 1062 | /* Populate regmap for the regmap backed clocks */ |
839 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++) | 1063 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) |
840 | meson8b_clk_dividers[i]->reg = clk_base + | 1064 | meson8b_clk_regmaps[i]->map = map; |
841 | (u32)meson8b_clk_dividers[i]->reg; | ||
842 | 1065 | ||
843 | /* | 1066 | /* |
844 | * register all clks | 1067 | * register all clks |
845 | * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 | 1068 | * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 |
846 | */ | 1069 | */ |
847 | for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { | 1070 | for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { |
848 | /* array might be sparse */ | 1071 | /* array might be sparse */ |
849 | if (!meson8b_hw_onecell_data.hws[clkid]) | 1072 | if (!meson8b_hw_onecell_data.hws[i]) |
850 | continue; | 1073 | continue; |
851 | 1074 | ||
852 | /* FIXME convert to devm_clk_register */ | 1075 | ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); |
853 | ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); | ||
854 | if (ret) | 1076 | if (ret) |
855 | return ret; | 1077 | return ret; |
856 | } | 1078 | } |
857 | 1079 | ||
858 | /* | 1080 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, |
859 | * Register CPU clk notifier | 1081 | &meson8b_hw_onecell_data); |
860 | * | ||
861 | * FIXME this is wrong for a lot of reasons. First, the muxes should be | ||
862 | * struct clk_hw objects. Second, we shouldn't program the muxes in | ||
863 | * notifier handlers. The tricky programming sequence will be handled | ||
864 | * by the forthcoming coordinated clock rates mechanism once that | ||
865 | * feature is released. | ||
866 | * | ||
867 | * Furthermore, looking up the parent this way is terrible. At some | ||
868 | * point we will stop allocating a default struct clk when registering | ||
869 | * a new clk_hw, and this hack will no longer work. Releasing the ccr | ||
870 | * feature before that time solves the problem :-) | ||
871 | */ | ||
872 | parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); | ||
873 | parent_clk = parent_hw->clk; | ||
874 | ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); | ||
875 | if (ret) { | ||
876 | pr_err("%s: failed to register clock notifier for cpu_clk\n", | ||
877 | __func__); | ||
878 | return ret; | ||
879 | } | ||
880 | |||
881 | return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||
882 | &meson8b_hw_onecell_data); | ||
883 | } | 1082 | } |
884 | 1083 | ||
885 | static const struct of_device_id meson8b_clkc_match_table[] = { | 1084 | static const struct of_device_id meson8b_clkc_match_table[] = { |