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