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