aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>2014-05-19 12:43:27 -0400
committerMike Turquette <mturquette@linaro.org>2014-05-29 12:30:19 -0400
commitba0fae3b06a69aab4ff18f628f88b9f9d653d734 (patch)
tree4fb6beb74a8a523782789dbd8665e66d3a41ab45 /drivers/clk
parent6f9ba9b44724888c5419289e790077ab1621c62d (diff)
clk: berlin: add core clock driver for BG2/BG2CD
This driver deals with the core clocks found on Marvell Berlin BG2 and BG2CD. For the shared register dividers, make use of the corresponding driver and add some single clock muxes and gates for the rest. Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/berlin/Makefile2
-rw-r--r--drivers/clk/berlin/bg2.c691
-rw-r--r--drivers/clk/berlin/common.h29
3 files changed, 722 insertions, 0 deletions
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index f0a7dc8b5e30..2b33e1e74503 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1,3 @@
1obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o 1obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
2obj-$(CONFIG_MACH_BERLIN_BG2) += bg2.o
3obj-$(CONFIG_MACH_BERLIN_BG2CD) += bg2.o
diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
new file mode 100644
index 000000000000..515fb133495c
--- /dev/null
+++ b/drivers/clk/berlin/bg2.c
@@ -0,0 +1,691 @@
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
95static struct clk *clks[MAX_CLKS];
96static struct clk_onecell_data clk_data;
97static DEFINE_SPINLOCK(lock);
98static void __iomem *gbase;
99
100enum {
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
113static 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
145static 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
153static const u8 default_parent_ids[] = {
154 SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
155};
156
157static 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
485static 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, CLK_IGNORE_UNUSED },
494 { "sdio1", "perif", 15, CLK_IGNORE_UNUSED },
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
503static void __init berlin2_clock_setup(struct device_node *np)
504{
505 const char *parent_names[9];
506 struct clk *clk;
507 u8 avpll_flags = 0;
508 int n;
509
510 gbase = of_iomap(np, 0);
511 if (!gbase)
512 return;
513
514 /* overwrite default clock names with DT provided ones */
515 clk = of_clk_get_by_name(np, clk_names[REFCLK]);
516 if (!IS_ERR(clk)) {
517 clk_names[REFCLK] = __clk_get_name(clk);
518 clk_put(clk);
519 }
520
521 clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]);
522 if (!IS_ERR(clk)) {
523 clk_names[VIDEO_EXT0] = __clk_get_name(clk);
524 clk_put(clk);
525 }
526
527 /* simple register PLLs */
528 clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
529 clk_names[SYSPLL], clk_names[REFCLK], 0);
530 if (IS_ERR(clk))
531 goto bg2_fail;
532
533 clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
534 clk_names[MEMPLL], clk_names[REFCLK], 0);
535 if (IS_ERR(clk))
536 goto bg2_fail;
537
538 clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
539 clk_names[CPUPLL], clk_names[REFCLK], 0);
540 if (IS_ERR(clk))
541 goto bg2_fail;
542
543 if (of_device_is_compatible(np, "marvell,berlin2-global-register"))
544 avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;
545
546 /* audio/video VCOs */
547 clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
548 clk_names[REFCLK], avpll_flags, 0);
549 if (IS_ERR(clk))
550 goto bg2_fail;
551
552 for (n = 0; n < 8; n++) {
553 clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
554 clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
555 avpll_flags, 0);
556 if (IS_ERR(clk))
557 goto bg2_fail;
558 }
559
560 clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
561 clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
562 avpll_flags, 0);
563 if (IS_ERR(clk))
564 goto bg2_fail;
565
566 for (n = 0; n < 8; n++) {
567 clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
568 clk_names[AVPLL_B1 + n], n, "avpll_vcoB",
569 BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);
570 if (IS_ERR(clk))
571 goto bg2_fail;
572 }
573
574 /* reference clock bypass switches */
575 parent_names[0] = clk_names[SYSPLL];
576 parent_names[1] = clk_names[REFCLK];
577 clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2,
578 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
579 if (IS_ERR(clk))
580 goto bg2_fail;
581 clk_names[SYSPLL] = __clk_get_name(clk);
582
583 parent_names[0] = clk_names[MEMPLL];
584 parent_names[1] = clk_names[REFCLK];
585 clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2,
586 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
587 if (IS_ERR(clk))
588 goto bg2_fail;
589 clk_names[MEMPLL] = __clk_get_name(clk);
590
591 parent_names[0] = clk_names[CPUPLL];
592 parent_names[1] = clk_names[REFCLK];
593 clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2,
594 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
595 if (IS_ERR(clk))
596 goto bg2_fail;
597 clk_names[CPUPLL] = __clk_get_name(clk);
598
599 /* clock muxes */
600 parent_names[0] = clk_names[AVPLL_B3];
601 parent_names[1] = clk_names[AVPLL_A3];
602 clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
603 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
604 if (IS_ERR(clk))
605 goto bg2_fail;
606
607 parent_names[0] = clk_names[VIDEO0_PLL];
608 parent_names[1] = clk_names[VIDEO_EXT0];
609 clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
610 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
611 if (IS_ERR(clk))
612 goto bg2_fail;
613
614 parent_names[0] = clk_names[VIDEO1_PLL];
615 parent_names[1] = clk_names[VIDEO_EXT0];
616 clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
617 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
618 if (IS_ERR(clk))
619 goto bg2_fail;
620
621 parent_names[0] = clk_names[AVPLL_A2];
622 parent_names[1] = clk_names[AVPLL_B2];
623 clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
624 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
625 if (IS_ERR(clk))
626 goto bg2_fail;
627
628 parent_names[0] = clk_names[VIDEO2_PLL];
629 parent_names[1] = clk_names[VIDEO_EXT0];
630 clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
631 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
632 if (IS_ERR(clk))
633 goto bg2_fail;
634
635 parent_names[0] = clk_names[AVPLL_B1];
636 parent_names[1] = clk_names[AVPLL_A5];
637 clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
638 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
639 if (IS_ERR(clk))
640 goto bg2_fail;
641
642 /* clock divider cells */
643 for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) {
644 const struct berlin2_div_data *dd = &bg2_divs[n];
645 int k;
646
647 for (k = 0; k < dd->num_parents; k++)
648 parent_names[k] = clk_names[dd->parent_ids[k]];
649
650 clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
651 dd->name, dd->div_flags, parent_names,
652 dd->num_parents, dd->flags, &lock);
653 }
654
655 /* clock gate cells */
656 for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
657 const struct berlin2_gate_data *gd = &bg2_gates[n];
658
659 clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name,
660 gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
661 gd->bit_idx, 0, &lock);
662 }
663
664 /* twdclk is derived from cpu/3 */
665 clks[CLKID_TWD] =
666 clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
667
668 /* check for errors on leaf clocks */
669 for (n = 0; n < MAX_CLKS; n++) {
670 if (!IS_ERR(clks[n]))
671 continue;
672
673 pr_err("%s: Unable to register leaf clock %d\n",
674 np->full_name, n);
675 goto bg2_fail;
676 }
677
678 /* register clk-provider */
679 clk_data.clks = clks;
680 clk_data.clk_num = MAX_CLKS;
681 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
682
683 return;
684
685bg2_fail:
686 iounmap(gbase);
687}
688CLK_OF_DECLARE(berlin2_clock, "marvell,berlin2-chip-ctrl",
689 berlin2_clock_setup);
690CLK_OF_DECLARE(berlin2cd_clock, "marvell,berlin2cd-chip-ctrl",
691 berlin2_clock_setup);
diff --git a/drivers/clk/berlin/common.h b/drivers/clk/berlin/common.h
new file mode 100644
index 000000000000..bc68a14c4550
--- /dev/null
+++ b/drivers/clk/berlin/common.h
@@ -0,0 +1,29 @@
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#ifndef __BERLIN2_COMMON_H
20#define __BERLIN2_COMMON_H
21
22struct berlin2_gate_data {
23 const char *name;
24 const char *parent_name;
25 u8 bit_idx;
26 unsigned long flags;
27};
28
29#endif /* BERLIN2_COMMON_H */