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
85static struct clk_hw_onecell_data *clk_data;
86static DEFINE_SPINLOCK(lock);
87static void __iomem *gbase;
88
89enum {
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
102static 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
134static 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
142static const u8 default_parent_ids[] = {
143	SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
144};
145
146static 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
474static 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
492static 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		of_node_put(parent_np);
505		return;
506	}
507	clk_data->num = MAX_CLKS;
508	hws = clk_data->hws;
509
510	gbase = of_iomap(parent_np, 0);
511	of_node_put(parent_np);
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	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
530				   clk_names[SYSPLL], clk_names[REFCLK], 0);
531	if (ret)
532		goto bg2_fail;
533
534	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
535				   clk_names[MEMPLL], clk_names[REFCLK], 0);
536	if (ret)
537		goto bg2_fail;
538
539	ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
540				   clk_names[CPUPLL], clk_names[REFCLK], 0);
541	if (ret)
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	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
549			 clk_names[REFCLK], avpll_flags, 0);
550	if (ret)
551		goto bg2_fail;
552
553	for (n = 0; n < 8; n++) {
554		ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
555			     clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
556			     avpll_flags, 0);
557		if (ret)
558			goto bg2_fail;
559	}
560
561	ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
562				 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
563				 avpll_flags, 0);
564	if (ret)
565		goto bg2_fail;
566
567	for (n = 0; n < 8; n++) {
568		ret = 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 (ret)
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	hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2,
579			       0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
580	if (IS_ERR(hw))
581		goto bg2_fail;
582	clk_names[SYSPLL] = clk_hw_get_name(hw);
583
584	parent_names[0] = clk_names[MEMPLL];
585	parent_names[1] = clk_names[REFCLK];
586	hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2,
587			       0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
588	if (IS_ERR(hw))
589		goto bg2_fail;
590	clk_names[MEMPLL] = clk_hw_get_name(hw);
591
592	parent_names[0] = clk_names[CPUPLL];
593	parent_names[1] = clk_names[REFCLK];
594	hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2,
595			       0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
596	if (IS_ERR(hw))
597		goto bg2_fail;
598	clk_names[CPUPLL] = clk_hw_get_name(hw);
599
600	/* clock muxes */
601	parent_names[0] = clk_names[AVPLL_B3];
602	parent_names[1] = clk_names[AVPLL_A3];
603	hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
604			       0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
605	if (IS_ERR(hw))
606		goto bg2_fail;
607
608	parent_names[0] = clk_names[VIDEO0_PLL];
609	parent_names[1] = clk_names[VIDEO_EXT0];
610	hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
611			       0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
612	if (IS_ERR(hw))
613		goto bg2_fail;
614
615	parent_names[0] = clk_names[VIDEO1_PLL];
616	parent_names[1] = clk_names[VIDEO_EXT0];
617	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
618			       0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
619	if (IS_ERR(hw))
620		goto bg2_fail;
621
622	parent_names[0] = clk_names[AVPLL_A2];
623	parent_names[1] = clk_names[AVPLL_B2];
624	hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
625			       0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
626	if (IS_ERR(hw))
627		goto bg2_fail;
628
629	parent_names[0] = clk_names[VIDEO2_PLL];
630	parent_names[1] = clk_names[VIDEO_EXT0];
631	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
632			       0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
633	if (IS_ERR(hw))
634		goto bg2_fail;
635
636	parent_names[0] = clk_names[AVPLL_B1];
637	parent_names[1] = clk_names[AVPLL_A5];
638	hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
639			       0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
640	if (IS_ERR(hw))
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		hws[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		hws[CLKID_GETH0 + n] = clk_hw_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	hws[CLKID_TWD] =
667		clk_hw_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(hws[n]))
672			continue;
673
674		pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
675		goto bg2_fail;
676	}
677
678	/* register clk-provider */
679	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
680
681	return;
682
683bg2_fail:
684	iounmap(gbase);
685}
686CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
687	       berlin2_clock_setup);
688