Merge branch 'for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
[linux-2.6-block.git] / drivers / clk / berlin / bg2.c
CommitLineData
ba0fae3b
SH
1/*
2 * Copyright (c) 2014 Marvell Technology Group Ltd.
3 *
4 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
5 * Alexandre Belloni <alexandre.belloni@free-electrons.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/clk.h>
21#include <linux/clk-provider.h>
22#include <linux/kernel.h>
23#include <linux/of.h>
24#include <linux/of_address.h>
25#include <linux/slab.h>
26
27#include <dt-bindings/clock/berlin2.h>
28
29#include "berlin2-avpll.h"
30#include "berlin2-div.h"
31#include "berlin2-pll.h"
32#include "common.h"
33
34#define REG_PINMUX0 0x0000
35#define REG_PINMUX1 0x0004
36#define REG_SYSPLLCTL0 0x0014
37#define REG_SYSPLLCTL4 0x0024
38#define REG_MEMPLLCTL0 0x0028
39#define REG_MEMPLLCTL4 0x0038
40#define REG_CPUPLLCTL0 0x003c
41#define REG_CPUPLLCTL4 0x004c
42#define REG_AVPLLCTL0 0x0050
43#define REG_AVPLLCTL31 0x00cc
44#define REG_AVPLLCTL62 0x0148
45#define REG_PLLSTATUS 0x014c
46#define REG_CLKENABLE 0x0150
47#define REG_CLKSELECT0 0x0154
48#define REG_CLKSELECT1 0x0158
49#define REG_CLKSELECT2 0x015c
50#define REG_CLKSELECT3 0x0160
51#define REG_CLKSWITCH0 0x0164
52#define REG_CLKSWITCH1 0x0168
53#define REG_RESET_TRIGGER 0x0178
54#define REG_RESET_STATUS0 0x017c
55#define REG_RESET_STATUS1 0x0180
56#define REG_SW_GENERIC0 0x0184
57#define REG_SW_GENERIC3 0x0190
58#define REG_PRODUCTID 0x01cc
59#define REG_PRODUCTID_EXT 0x01d0
60#define REG_GFX3DCORE_CLKCTL 0x022c
61#define REG_GFX3DSYS_CLKCTL 0x0230
62#define REG_ARC_CLKCTL 0x0234
63#define REG_VIP_CLKCTL 0x0238
64#define REG_SDIO0XIN_CLKCTL 0x023c
65#define REG_SDIO1XIN_CLKCTL 0x0240
66#define REG_GFX3DEXTRA_CLKCTL 0x0244
67#define REG_GFX3D_RESET 0x0248
68#define REG_GC360_CLKCTL 0x024c
69#define REG_SDIO_DLLMST_CLKCTL 0x0250
70
71/*
72 * BG2/BG2CD SoCs have the following audio/video I/O units:
73 *
74 * audiohd: HDMI TX audio
75 * audio0: 7.1ch TX
76 * audio1: 2ch TX
77 * audio2: 2ch RX
78 * audio3: SPDIF TX
79 * video0: HDMI video
80 * video1: Secondary video
81 * video2: SD auxiliary video
82 *
83 * There are no external audio clocks (ACLKI0, ACLKI1) and
84 * only one external video clock (VCLKI0).
85 *
86 * Currently missing bits and pieces:
87 * - audio_fast_pll is unknown
88 * - audiohd_pll is unknown
89 * - video0_pll is unknown
90 * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
91 *
92 */
93
94#define MAX_CLKS 41
f6475e29 95static struct clk_hw_onecell_data *clk_data;
ba0fae3b
SH
96static DEFINE_SPINLOCK(lock);
97static void __iomem *gbase;
98
99enum {
100 REFCLK, VIDEO_EXT0,
101 SYSPLL, MEMPLL, CPUPLL,
102 AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4,
103 AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8,
104 AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
105 AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
106 AUDIO1_PLL, AUDIO_FAST_PLL,
107 VIDEO0_PLL, VIDEO0_IN,
108 VIDEO1_PLL, VIDEO1_IN,
109 VIDEO2_PLL, VIDEO2_IN,
110};
111
112static const char *clk_names[] = {
113 [REFCLK] = "refclk",
114 [VIDEO_EXT0] = "video_ext0",
115 [SYSPLL] = "syspll",
116 [MEMPLL] = "mempll",
117 [CPUPLL] = "cpupll",
118 [AVPLL_A1] = "avpll_a1",
119 [AVPLL_A2] = "avpll_a2",
120 [AVPLL_A3] = "avpll_a3",
121 [AVPLL_A4] = "avpll_a4",
122 [AVPLL_A5] = "avpll_a5",
123 [AVPLL_A6] = "avpll_a6",
124 [AVPLL_A7] = "avpll_a7",
125 [AVPLL_A8] = "avpll_a8",
126 [AVPLL_B1] = "avpll_b1",
127 [AVPLL_B2] = "avpll_b2",
128 [AVPLL_B3] = "avpll_b3",
129 [AVPLL_B4] = "avpll_b4",
130 [AVPLL_B5] = "avpll_b5",
131 [AVPLL_B6] = "avpll_b6",
132 [AVPLL_B7] = "avpll_b7",
133 [AVPLL_B8] = "avpll_b8",
134 [AUDIO1_PLL] = "audio1_pll",
135 [AUDIO_FAST_PLL] = "audio_fast_pll",
136 [VIDEO0_PLL] = "video0_pll",
137 [VIDEO0_IN] = "video0_in",
138 [VIDEO1_PLL] = "video1_pll",
139 [VIDEO1_IN] = "video1_in",
140 [VIDEO2_PLL] = "video2_pll",
141 [VIDEO2_IN] = "video2_in",
142};
143
144static const struct berlin2_pll_map bg2_pll_map __initconst = {
145 .vcodiv = {10, 15, 20, 25, 30, 40, 50, 60, 80},
146 .mult = 10,
147 .fbdiv_shift = 6,
148 .rfdiv_shift = 1,
149 .divsel_shift = 7,
150};
151
152static const u8 default_parent_ids[] = {
153 SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
154};
155
156static const struct berlin2_div_data bg2_divs[] __initconst = {
157 {
158 .name = "sys",
159 .parent_ids = (const u8 []){
160 SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
161 },
162 .num_parents = 6,
163 .map = {
164 BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
165 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
166 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
167 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
168 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
169 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
170 },
171 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
172 .flags = CLK_IGNORE_UNUSED,
173 },
174 {
175 .name = "cpu",
176 .parent_ids = (const u8 []){
177 CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL
178 },
179 .num_parents = 5,
180 .map = {
181 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
182 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
183 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
184 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
185 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
186 },
187 .div_flags = BERLIN2_DIV_HAS_MUX,
188 .flags = 0,
189 },
190 {
191 .name = "drmfigo",
192 .parent_ids = default_parent_ids,
193 .num_parents = ARRAY_SIZE(default_parent_ids),
194 .map = {
195 BERLIN2_DIV_GATE(REG_CLKENABLE, 16),
196 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),
197 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),
198 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
199 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
200 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
201 },
202 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
203 .flags = 0,
204 },
205 {
206 .name = "cfg",
207 .parent_ids = default_parent_ids,
208 .num_parents = ARRAY_SIZE(default_parent_ids),
209 .map = {
210 BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
211 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),
212 BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),
213 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
214 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
215 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
216 },
217 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
218 .flags = 0,
219 },
220 {
221 .name = "gfx",
222 .parent_ids = default_parent_ids,
223 .num_parents = ARRAY_SIZE(default_parent_ids),
224 .map = {
225 BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
226 BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),
227 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),
228 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
229 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
230 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
231 },
232 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
233 .flags = 0,
234 },
235 {
236 .name = "zsp",
237 .parent_ids = default_parent_ids,
238 .num_parents = ARRAY_SIZE(default_parent_ids),
239 .map = {
240 BERLIN2_DIV_GATE(REG_CLKENABLE, 5),
241 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),
242 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),
243 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
244 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
245 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
246 },
247 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
248 .flags = 0,
249 },
250 {
251 .name = "perif",
252 .parent_ids = default_parent_ids,
253 .num_parents = ARRAY_SIZE(default_parent_ids),
254 .map = {
255 BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
256 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),
257 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),
258 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
259 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
260 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
261 },
262 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
263 .flags = CLK_IGNORE_UNUSED,
264 },
265 {
266 .name = "pcube",
267 .parent_ids = default_parent_ids,
268 .num_parents = ARRAY_SIZE(default_parent_ids),
269 .map = {
270 BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
271 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),
272 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),
273 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
274 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
275 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
276 },
277 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
278 .flags = 0,
279 },
280 {
281 .name = "vscope",
282 .parent_ids = default_parent_ids,
283 .num_parents = ARRAY_SIZE(default_parent_ids),
284 .map = {
285 BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
286 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),
287 BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),
288 BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
289 BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
290 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
291 },
292 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
293 .flags = 0,
294 },
295 {
296 .name = "nfc_ecc",
297 .parent_ids = default_parent_ids,
298 .num_parents = ARRAY_SIZE(default_parent_ids),
299 .map = {
300 BERLIN2_DIV_GATE(REG_CLKENABLE, 18),
301 BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),
302 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),
303 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
304 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
305 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
306 },
307 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
308 .flags = 0,
309 },
310 {
311 .name = "vpp",
312 .parent_ids = default_parent_ids,
313 .num_parents = ARRAY_SIZE(default_parent_ids),
314 .map = {
315 BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
316 BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),
317 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),
318 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),
319 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),
320 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),
321 },
322 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
323 .flags = 0,
324 },
325 {
326 .name = "app",
327 .parent_ids = default_parent_ids,
328 .num_parents = ARRAY_SIZE(default_parent_ids),
329 .map = {
330 BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
331 BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),
332 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),
333 BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),
334 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),
335 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),
336 },
337 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
338 .flags = 0,
339 },
340 {
341 .name = "audio0",
342 .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
343 .num_parents = 1,
344 .map = {
345 BERLIN2_DIV_GATE(REG_CLKENABLE, 22),
346 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),
347 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),
348 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),
349 },
350 .div_flags = BERLIN2_DIV_HAS_GATE,
351 .flags = 0,
352 },
353 {
354 .name = "audio2",
355 .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
356 .num_parents = 1,
357 .map = {
358 BERLIN2_DIV_GATE(REG_CLKENABLE, 24),
359 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),
360 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),
361 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),
362 },
363 .div_flags = BERLIN2_DIV_HAS_GATE,
364 .flags = 0,
365 },
366 {
367 .name = "audio3",
368 .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
369 .num_parents = 1,
370 .map = {
371 BERLIN2_DIV_GATE(REG_CLKENABLE, 25),
372 BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),
373 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),
374 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),
375 },
376 .div_flags = BERLIN2_DIV_HAS_GATE,
377 .flags = 0,
378 },
379 {
380 .name = "audio1",
381 .parent_ids = (const u8 []){ AUDIO1_PLL },
382 .num_parents = 1,
383 .map = {
384 BERLIN2_DIV_GATE(REG_CLKENABLE, 23),
385 BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),
386 BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),
387 BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),
388 },
389 .div_flags = BERLIN2_DIV_HAS_GATE,
390 .flags = 0,
391 },
392 {
393 .name = "gfx3d_core",
394 .parent_ids = default_parent_ids,
395 .num_parents = ARRAY_SIZE(default_parent_ids),
396 .map = {
397 BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL),
398 },
399 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
400 .flags = 0,
401 },
402 {
403 .name = "gfx3d_sys",
404 .parent_ids = default_parent_ids,
405 .num_parents = ARRAY_SIZE(default_parent_ids),
406 .map = {
407 BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL),
408 },
409 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
410 .flags = 0,
411 },
412 {
413 .name = "arc",
414 .parent_ids = default_parent_ids,
415 .num_parents = ARRAY_SIZE(default_parent_ids),
416 .map = {
417 BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL),
418 },
419 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
420 .flags = 0,
421 },
422 {
423 .name = "vip",
424 .parent_ids = default_parent_ids,
425 .num_parents = ARRAY_SIZE(default_parent_ids),
426 .map = {
427 BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL),
428 },
429 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
430 .flags = 0,
431 },
432 {
433 .name = "sdio0xin",
434 .parent_ids = default_parent_ids,
435 .num_parents = ARRAY_SIZE(default_parent_ids),
436 .map = {
437 BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
438 },
439 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
440 .flags = 0,
441 },
442 {
443 .name = "sdio1xin",
444 .parent_ids = default_parent_ids,
445 .num_parents = ARRAY_SIZE(default_parent_ids),
446 .map = {
447 BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
448 },
449 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
450 .flags = 0,
451 },
452 {
453 .name = "gfx3d_extra",
454 .parent_ids = default_parent_ids,
455 .num_parents = ARRAY_SIZE(default_parent_ids),
456 .map = {
457 BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL),
458 },
459 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
460 .flags = 0,
461 },
462 {
463 .name = "gc360",
464 .parent_ids = default_parent_ids,
465 .num_parents = ARRAY_SIZE(default_parent_ids),
466 .map = {
467 BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL),
468 },
469 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
470 .flags = 0,
471 },
472 {
473 .name = "sdio_dllmst",
474 .parent_ids = default_parent_ids,
475 .num_parents = ARRAY_SIZE(default_parent_ids),
476 .map = {
477 BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL),
478 },
479 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
480 .flags = 0,
481 },
482};
483
484static const struct berlin2_gate_data bg2_gates[] __initconst = {
485 { "geth0", "perif", 7 },
486 { "geth1", "perif", 8 },
487 { "sata", "perif", 9 },
488 { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED },
489 { "usb0", "perif", 11 },
490 { "usb1", "perif", 12 },
491 { "pbridge", "perif", 13, CLK_IGNORE_UNUSED },
1256f10f
JZ
492 { "sdio0", "perif", 14 },
493 { "sdio1", "perif", 15 },
ba0fae3b
SH
494 { "nfc", "perif", 17 },
495 { "smemc", "perif", 19 },
496 { "audiohd", "audiohd_pll", 26 },
497 { "video0", "video0_in", 27 },
498 { "video1", "video1_in", 28 },
499 { "video2", "video2_in", 29 },
500};
501
502static void __init berlin2_clock_setup(struct device_node *np)
503{
26b3b6b9 504 struct device_node *parent_np = of_get_parent(np);
ba0fae3b
SH
505 const char *parent_names[9];
506 struct clk *clk;
f6475e29
SB
507 struct clk_hw *hw;
508 struct clk_hw **hws;
ba0fae3b 509 u8 avpll_flags = 0;
f6475e29
SB
510 int n, ret;
511
512 clk_data = kzalloc(sizeof(*clk_data) +
513 sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL);
514 if (!clk_data)
515 return;
516 clk_data->num = MAX_CLKS;
517 hws = clk_data->hws;
ba0fae3b 518
fd26031b 519 gbase = of_iomap(parent_np, 0);
ba0fae3b
SH
520 if (!gbase)
521 return;
522
523 /* overwrite default clock names with DT provided ones */
524 clk = of_clk_get_by_name(np, clk_names[REFCLK]);
525 if (!IS_ERR(clk)) {
526 clk_names[REFCLK] = __clk_get_name(clk);
527 clk_put(clk);
528 }
529
530 clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]);
531 if (!IS_ERR(clk)) {
532 clk_names[VIDEO_EXT0] = __clk_get_name(clk);
533 clk_put(clk);
534 }
535
536 /* simple register PLLs */
f6475e29 537 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
ba0fae3b 538 clk_names[SYSPLL], clk_names[REFCLK], 0);
f6475e29 539 if (ret)
ba0fae3b
SH
540 goto bg2_fail;
541
f6475e29 542 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
ba0fae3b 543 clk_names[MEMPLL], clk_names[REFCLK], 0);
f6475e29 544 if (ret)
ba0fae3b
SH
545 goto bg2_fail;
546
f6475e29 547 ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
ba0fae3b 548 clk_names[CPUPLL], clk_names[REFCLK], 0);
f6475e29 549 if (ret)
ba0fae3b
SH
550 goto bg2_fail;
551
552 if (of_device_is_compatible(np, "marvell,berlin2-global-register"))
553 avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;
554
555 /* audio/video VCOs */
f6475e29 556 ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
ba0fae3b 557 clk_names[REFCLK], avpll_flags, 0);
f6475e29 558 if (ret)
ba0fae3b
SH
559 goto bg2_fail;
560
561 for (n = 0; n < 8; n++) {
f6475e29 562 ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
ba0fae3b
SH
563 clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
564 avpll_flags, 0);
f6475e29 565 if (ret)
ba0fae3b
SH
566 goto bg2_fail;
567 }
568
f6475e29 569 ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
ba0fae3b
SH
570 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
571 avpll_flags, 0);
f6475e29 572 if (ret)
ba0fae3b
SH
573 goto bg2_fail;
574
575 for (n = 0; n < 8; n++) {
f6475e29 576 ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
ba0fae3b
SH
577 clk_names[AVPLL_B1 + n], n, "avpll_vcoB",
578 BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);
f6475e29 579 if (ret)
ba0fae3b
SH
580 goto bg2_fail;
581 }
582
583 /* reference clock bypass switches */
584 parent_names[0] = clk_names[SYSPLL];
585 parent_names[1] = clk_names[REFCLK];
f6475e29 586 hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2,
ba0fae3b 587 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
f6475e29 588 if (IS_ERR(hw))
ba0fae3b 589 goto bg2_fail;
f6475e29 590 clk_names[SYSPLL] = clk_hw_get_name(hw);
ba0fae3b
SH
591
592 parent_names[0] = clk_names[MEMPLL];
593 parent_names[1] = clk_names[REFCLK];
f6475e29 594 hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2,
ba0fae3b 595 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
f6475e29 596 if (IS_ERR(hw))
ba0fae3b 597 goto bg2_fail;
f6475e29 598 clk_names[MEMPLL] = clk_hw_get_name(hw);
ba0fae3b
SH
599
600 parent_names[0] = clk_names[CPUPLL];
601 parent_names[1] = clk_names[REFCLK];
f6475e29 602 hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2,
ba0fae3b 603 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
f6475e29 604 if (IS_ERR(hw))
ba0fae3b 605 goto bg2_fail;
f6475e29 606 clk_names[CPUPLL] = clk_hw_get_name(hw);
ba0fae3b
SH
607
608 /* clock muxes */
609 parent_names[0] = clk_names[AVPLL_B3];
610 parent_names[1] = clk_names[AVPLL_A3];
f6475e29 611 hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
ba0fae3b 612 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
f6475e29 613 if (IS_ERR(hw))
ba0fae3b
SH
614 goto bg2_fail;
615
616 parent_names[0] = clk_names[VIDEO0_PLL];
617 parent_names[1] = clk_names[VIDEO_EXT0];
f6475e29 618 hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
ba0fae3b 619 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
f6475e29 620 if (IS_ERR(hw))
ba0fae3b
SH
621 goto bg2_fail;
622
623 parent_names[0] = clk_names[VIDEO1_PLL];
624 parent_names[1] = clk_names[VIDEO_EXT0];
f6475e29 625 hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
ba0fae3b 626 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
f6475e29 627 if (IS_ERR(hw))
ba0fae3b
SH
628 goto bg2_fail;
629
630 parent_names[0] = clk_names[AVPLL_A2];
631 parent_names[1] = clk_names[AVPLL_B2];
f6475e29 632 hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
ba0fae3b 633 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
f6475e29 634 if (IS_ERR(hw))
ba0fae3b
SH
635 goto bg2_fail;
636
637 parent_names[0] = clk_names[VIDEO2_PLL];
638 parent_names[1] = clk_names[VIDEO_EXT0];
f6475e29 639 hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
ba0fae3b 640 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
f6475e29 641 if (IS_ERR(hw))
ba0fae3b
SH
642 goto bg2_fail;
643
644 parent_names[0] = clk_names[AVPLL_B1];
645 parent_names[1] = clk_names[AVPLL_A5];
f6475e29 646 hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
ba0fae3b 647 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
f6475e29 648 if (IS_ERR(hw))
ba0fae3b
SH
649 goto bg2_fail;
650
651 /* clock divider cells */
652 for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) {
653 const struct berlin2_div_data *dd = &bg2_divs[n];
654 int k;
655
656 for (k = 0; k < dd->num_parents; k++)
657 parent_names[k] = clk_names[dd->parent_ids[k]];
658
f6475e29 659 hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
ba0fae3b
SH
660 dd->name, dd->div_flags, parent_names,
661 dd->num_parents, dd->flags, &lock);
662 }
663
664 /* clock gate cells */
665 for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
666 const struct berlin2_gate_data *gd = &bg2_gates[n];
667
f6475e29 668 hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name,
ba0fae3b
SH
669 gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
670 gd->bit_idx, 0, &lock);
671 }
672
673 /* twdclk is derived from cpu/3 */
f6475e29
SB
674 hws[CLKID_TWD] =
675 clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
ba0fae3b
SH
676
677 /* check for errors on leaf clocks */
678 for (n = 0; n < MAX_CLKS; n++) {
f6475e29 679 if (!IS_ERR(hws[n]))
ba0fae3b
SH
680 continue;
681
682 pr_err("%s: Unable to register leaf clock %d\n",
683 np->full_name, n);
684 goto bg2_fail;
685 }
686
687 /* register clk-provider */
3ca0b51d 688 of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
ba0fae3b
SH
689
690 return;
691
692bg2_fail:
693 iounmap(gbase);
694}
26b3b6b9
AT
695CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
696 berlin2_clock_setup);