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