xref: /linux/drivers/clk/berlin/bg2.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
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_hw_onecell_data *clk_data;
96 static DEFINE_SPINLOCK(lock);
97 static void __iomem *gbase;
98 
99 enum {
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 
112 static 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 
144 static 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 
152 static const u8 default_parent_ids[] = {
153 	SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
154 };
155 
156 static 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 
484 static 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 },
492 	{ "sdio0",	"perif",	14 },
493 	{ "sdio1",	"perif",	15 },
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 
502 static void __init berlin2_clock_setup(struct device_node *np)
503 {
504 	struct device_node *parent_np = of_get_parent(np);
505 	const char *parent_names[9];
506 	struct clk *clk;
507 	struct clk_hw *hw;
508 	struct clk_hw **hws;
509 	u8 avpll_flags = 0;
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;
518 
519 	gbase = of_iomap(parent_np, 0);
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 */
537 	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
538 				   clk_names[SYSPLL], clk_names[REFCLK], 0);
539 	if (ret)
540 		goto bg2_fail;
541 
542 	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
543 				   clk_names[MEMPLL], clk_names[REFCLK], 0);
544 	if (ret)
545 		goto bg2_fail;
546 
547 	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
548 				   clk_names[CPUPLL], clk_names[REFCLK], 0);
549 	if (ret)
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 */
556 	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
557 			 clk_names[REFCLK], avpll_flags, 0);
558 	if (ret)
559 		goto bg2_fail;
560 
561 	for (n = 0; n < 8; n++) {
562 		ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
563 			     clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
564 			     avpll_flags, 0);
565 		if (ret)
566 			goto bg2_fail;
567 	}
568 
569 	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
570 				 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
571 				 avpll_flags, 0);
572 	if (ret)
573 		goto bg2_fail;
574 
575 	for (n = 0; n < 8; n++) {
576 		ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
577 			     clk_names[AVPLL_B1 + n], n, "avpll_vcoB",
578 			     BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);
579 		if (ret)
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];
586 	hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2,
587 			       0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
588 	if (IS_ERR(hw))
589 		goto bg2_fail;
590 	clk_names[SYSPLL] = clk_hw_get_name(hw);
591 
592 	parent_names[0] = clk_names[MEMPLL];
593 	parent_names[1] = clk_names[REFCLK];
594 	hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2,
595 			       0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
596 	if (IS_ERR(hw))
597 		goto bg2_fail;
598 	clk_names[MEMPLL] = clk_hw_get_name(hw);
599 
600 	parent_names[0] = clk_names[CPUPLL];
601 	parent_names[1] = clk_names[REFCLK];
602 	hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2,
603 			       0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
604 	if (IS_ERR(hw))
605 		goto bg2_fail;
606 	clk_names[CPUPLL] = clk_hw_get_name(hw);
607 
608 	/* clock muxes */
609 	parent_names[0] = clk_names[AVPLL_B3];
610 	parent_names[1] = clk_names[AVPLL_A3];
611 	hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
612 			       0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
613 	if (IS_ERR(hw))
614 		goto bg2_fail;
615 
616 	parent_names[0] = clk_names[VIDEO0_PLL];
617 	parent_names[1] = clk_names[VIDEO_EXT0];
618 	hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
619 			       0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
620 	if (IS_ERR(hw))
621 		goto bg2_fail;
622 
623 	parent_names[0] = clk_names[VIDEO1_PLL];
624 	parent_names[1] = clk_names[VIDEO_EXT0];
625 	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
626 			       0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
627 	if (IS_ERR(hw))
628 		goto bg2_fail;
629 
630 	parent_names[0] = clk_names[AVPLL_A2];
631 	parent_names[1] = clk_names[AVPLL_B2];
632 	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
633 			       0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
634 	if (IS_ERR(hw))
635 		goto bg2_fail;
636 
637 	parent_names[0] = clk_names[VIDEO2_PLL];
638 	parent_names[1] = clk_names[VIDEO_EXT0];
639 	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
640 			       0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
641 	if (IS_ERR(hw))
642 		goto bg2_fail;
643 
644 	parent_names[0] = clk_names[AVPLL_B1];
645 	parent_names[1] = clk_names[AVPLL_A5];
646 	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
647 			       0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
648 	if (IS_ERR(hw))
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 
659 		hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
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 
668 		hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name,
669 			    gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
670 			    gd->bit_idx, 0, &lock);
671 	}
672 
673 	/* twdclk is derived from cpu/3 */
674 	hws[CLKID_TWD] =
675 		clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
676 
677 	/* check for errors on leaf clocks */
678 	for (n = 0; n < MAX_CLKS; n++) {
679 		if (!IS_ERR(hws[n]))
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 */
688 	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
689 
690 	return;
691 
692 bg2_fail:
693 	iounmap(gbase);
694 }
695 CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
696 	       berlin2_clock_setup);
697