Linux 4.16.11
[linux/fpc-iii.git] / drivers / clk / berlin / bg2.c
blobe7331ace0337cc564bb3b3114d4f21063f8a849f
1 /*
2 * Copyright (c) 2014 Marvell Technology Group Ltd.
4 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
5 * Alexandre Belloni <alexandre.belloni@free-electrons.com>
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.
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.
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/>.
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>
27 #include <dt-bindings/clock/berlin2.h>
29 #include "berlin2-avpll.h"
30 #include "berlin2-div.h"
31 #include "berlin2-pll.h"
32 #include "common.h"
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
72 * BG2/BG2CD SoCs have the following audio/video I/O units:
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
83 * There are no external audio clocks (ACLKI0, ACLKI1) and
84 * only one external video clock (VCLKI0).
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
94 #define MAX_CLKS 41
95 static struct clk_hw_onecell_data *clk_data;
96 static DEFINE_SPINLOCK(lock);
97 static void __iomem *gbase;
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,
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",
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,
152 static const u8 default_parent_ids[] = {
153 SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
156 static const struct berlin2_div_data bg2_divs[] __initconst = {
158 .name = "sys",
159 .parent_ids = (const u8 []){
160 SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
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),
171 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
172 .flags = CLK_IGNORE_UNUSED,
175 .name = "cpu",
176 .parent_ids = (const u8 []){
177 CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL
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),
187 .div_flags = BERLIN2_DIV_HAS_MUX,
188 .flags = 0,
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),
202 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
203 .flags = 0,
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),
217 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
218 .flags = 0,
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),
232 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
233 .flags = 0,
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),
247 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
248 .flags = 0,
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),
262 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
263 .flags = CLK_IGNORE_UNUSED,
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),
277 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
278 .flags = 0,
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),
292 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
293 .flags = 0,
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),
307 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
308 .flags = 0,
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),
322 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
323 .flags = 0,
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),
337 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
338 .flags = 0,
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),
350 .div_flags = BERLIN2_DIV_HAS_GATE,
351 .flags = 0,
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),
363 .div_flags = BERLIN2_DIV_HAS_GATE,
364 .flags = 0,
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),
376 .div_flags = BERLIN2_DIV_HAS_GATE,
377 .flags = 0,
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),
389 .div_flags = BERLIN2_DIV_HAS_GATE,
390 .flags = 0,
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),
399 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
400 .flags = 0,
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),
409 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
410 .flags = 0,
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),
419 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
420 .flags = 0,
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),
429 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
430 .flags = 0,
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),
439 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
440 .flags = 0,
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),
449 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
450 .flags = 0,
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),
459 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
460 .flags = 0,
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),
469 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
470 .flags = 0,
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),
479 .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
480 .flags = 0,
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 },
502 static void __init berlin2_clock_setup(struct device_node *np)
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;
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;
519 gbase = of_iomap(parent_np, 0);
520 if (!gbase)
521 return;
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);
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);
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;
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;
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;
552 if (of_device_is_compatible(np, "marvell,berlin2-global-register"))
553 avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;
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;
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;
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;
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;
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);
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);
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);
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;
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;
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;
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;
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;
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;
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;
656 for (k = 0; k < dd->num_parents; k++)
657 parent_names[k] = clk_names[dd->parent_ids[k]];
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);
664 /* clock gate cells */
665 for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
666 const struct berlin2_gate_data *gd = &bg2_gates[n];
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);
673 /* twdclk is derived from cpu/3 */
674 hws[CLKID_TWD] =
675 clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
677 /* check for errors on leaf clocks */
678 for (n = 0; n < MAX_CLKS; n++) {
679 if (!IS_ERR(hws[n]))
680 continue;
682 pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
683 goto bg2_fail;
686 /* register clk-provider */
687 of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
689 return;
691 bg2_fail:
692 iounmap(gbase);
694 CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
695 berlin2_clock_setup);