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