xref: /openbmc/linux/drivers/clk/berlin/bg2q.c (revision db181ce0)
1 /*
2  * Copyright (c) 2014 Marvell Technology Group Ltd.
3  *
4  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
5  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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/berlin2q.h>
28 
29 #include "berlin2-div.h"
30 #include "berlin2-pll.h"
31 #include "common.h"
32 
33 #define REG_PINMUX0		0x0018
34 #define REG_PINMUX5		0x002c
35 #define REG_SYSPLLCTL0		0x0030
36 #define REG_SYSPLLCTL4		0x0040
37 #define REG_CLKENABLE		0x00e8
38 #define REG_CLKSELECT0		0x00ec
39 #define REG_CLKSELECT1		0x00f0
40 #define REG_CLKSELECT2		0x00f4
41 #define REG_CLKSWITCH0		0x00f8
42 #define REG_CLKSWITCH1		0x00fc
43 #define REG_SW_GENERIC0		0x0110
44 #define REG_SW_GENERIC3		0x011c
45 #define REG_SDIO0XIN_CLKCTL	0x0158
46 #define REG_SDIO1XIN_CLKCTL	0x015c
47 
48 #define	MAX_CLKS 27
49 static struct clk *clks[MAX_CLKS];
50 static struct clk_onecell_data clk_data;
51 static DEFINE_SPINLOCK(lock);
52 static void __iomem *gbase;
53 static void __iomem *cpupll_base;
54 
55 enum {
56 	REFCLK,
57 	SYSPLL, CPUPLL,
58 	AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
59 	AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
60 };
61 
62 static const char *clk_names[] = {
63 	[REFCLK]		= "refclk",
64 	[SYSPLL]		= "syspll",
65 	[CPUPLL]		= "cpupll",
66 	[AVPLL_B1]		= "avpll_b1",
67 	[AVPLL_B2]		= "avpll_b2",
68 	[AVPLL_B3]		= "avpll_b3",
69 	[AVPLL_B4]		= "avpll_b4",
70 	[AVPLL_B5]		= "avpll_b5",
71 	[AVPLL_B6]		= "avpll_b6",
72 	[AVPLL_B7]		= "avpll_b7",
73 	[AVPLL_B8]		= "avpll_b8",
74 };
75 
76 static const struct berlin2_pll_map bg2q_pll_map __initconst = {
77 	.vcodiv		= {1, 0, 2, 0, 3, 4, 0, 6, 8},
78 	.mult		= 1,
79 	.fbdiv_shift	= 7,
80 	.rfdiv_shift	= 2,
81 	.divsel_shift	= 9,
82 };
83 
84 static const u8 default_parent_ids[] = {
85 	SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
86 };
87 
88 static const struct berlin2_div_data bg2q_divs[] __initconst = {
89 	{
90 		.name = "sys",
91 		.parent_ids = default_parent_ids,
92 		.num_parents = ARRAY_SIZE(default_parent_ids),
93 		.map = {
94 			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
95 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
96 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
97 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
98 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
99 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
100 		},
101 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
102 		.flags = CLK_IGNORE_UNUSED,
103 	},
104 	{
105 		.name = "drmfigo",
106 		.parent_ids = default_parent_ids,
107 		.num_parents = ARRAY_SIZE(default_parent_ids),
108 		.map = {
109 			BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
110 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
111 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
112 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
113 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
114 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
115 		},
116 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
117 		.flags = 0,
118 	},
119 	{
120 		.name = "cfg",
121 		.parent_ids = default_parent_ids,
122 		.num_parents = ARRAY_SIZE(default_parent_ids),
123 		.map = {
124 			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
125 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
126 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
127 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
128 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
129 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
130 		},
131 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
132 		.flags = 0,
133 	},
134 	{
135 		.name = "gfx2d",
136 		.parent_ids = default_parent_ids,
137 		.num_parents = ARRAY_SIZE(default_parent_ids),
138 		.map = {
139 			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
140 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
141 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
142 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
143 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
144 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
145 		},
146 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
147 		.flags = 0,
148 	},
149 	{
150 		.name = "zsp",
151 		.parent_ids = default_parent_ids,
152 		.num_parents = ARRAY_SIZE(default_parent_ids),
153 		.map = {
154 			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
155 			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
156 			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
157 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
158 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
159 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
160 		},
161 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
162 		.flags = 0,
163 	},
164 	{
165 		.name = "perif",
166 		.parent_ids = default_parent_ids,
167 		.num_parents = ARRAY_SIZE(default_parent_ids),
168 		.map = {
169 			BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
170 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
171 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
172 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
173 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
174 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
175 		},
176 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
177 		.flags = CLK_IGNORE_UNUSED,
178 	},
179 	{
180 		.name = "pcube",
181 		.parent_ids = default_parent_ids,
182 		.num_parents = ARRAY_SIZE(default_parent_ids),
183 		.map = {
184 			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
185 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
186 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
187 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
188 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
189 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
190 		},
191 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
192 		.flags = 0,
193 	},
194 	{
195 		.name = "vscope",
196 		.parent_ids = default_parent_ids,
197 		.num_parents = ARRAY_SIZE(default_parent_ids),
198 		.map = {
199 			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
200 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
201 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
202 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
203 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
204 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
205 		},
206 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
207 		.flags = 0,
208 	},
209 	{
210 		.name = "nfc_ecc",
211 		.parent_ids = default_parent_ids,
212 		.num_parents = ARRAY_SIZE(default_parent_ids),
213 		.map = {
214 			BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
215 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
216 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
217 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
218 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
219 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
220 		},
221 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
222 		.flags = 0,
223 	},
224 	{
225 		.name = "vpp",
226 		.parent_ids = default_parent_ids,
227 		.num_parents = ARRAY_SIZE(default_parent_ids),
228 		.map = {
229 			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
230 			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
231 			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
232 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
233 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
234 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
235 		},
236 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
237 		.flags = 0,
238 	},
239 	{
240 		.name = "app",
241 		.parent_ids = default_parent_ids,
242 		.num_parents = ARRAY_SIZE(default_parent_ids),
243 		.map = {
244 			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
245 			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
246 			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
247 			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
248 			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
249 			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
250 		},
251 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
252 		.flags = 0,
253 	},
254 	{
255 		.name = "sdio0xin",
256 		.parent_ids = default_parent_ids,
257 		.num_parents = ARRAY_SIZE(default_parent_ids),
258 		.map = {
259 			BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
260 		},
261 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
262 		.flags = 0,
263 	},
264 	{
265 		.name = "sdio1xin",
266 		.parent_ids = default_parent_ids,
267 		.num_parents = ARRAY_SIZE(default_parent_ids),
268 		.map = {
269 			BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
270 		},
271 		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
272 		.flags = 0,
273 	},
274 };
275 
276 static const struct berlin2_gate_data bg2q_gates[] __initconst = {
277 	{ "gfx2daxi",	"perif",	5 },
278 	{ "geth0",	"perif",	8 },
279 	{ "sata",	"perif",	9 },
280 	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
281 	{ "usb0",	"perif",	11 },
282 	{ "usb1",	"perif",	12 },
283 	{ "usb2",	"perif",	13 },
284 	{ "usb3",	"perif",	14 },
285 	{ "pbridge",	"perif",	15, CLK_IGNORE_UNUSED },
286 	{ "sdio",	"perif",	16, CLK_IGNORE_UNUSED },
287 	{ "nfc",	"perif",	18 },
288 	{ "smemc",	"perif",	19 },
289 	{ "pcie",	"perif",	22 },
290 };
291 
292 static void __init berlin2q_clock_setup(struct device_node *np)
293 {
294 	const char *parent_names[9];
295 	struct clk *clk;
296 	int n;
297 
298 	gbase = of_iomap(np, 0);
299 	if (!gbase) {
300 		pr_err("%s: Unable to map global base\n", np->full_name);
301 		return;
302 	}
303 
304 	/* BG2Q CPU PLL is not part of global registers */
305 	cpupll_base = of_iomap(np, 1);
306 	if (!cpupll_base) {
307 		pr_err("%s: Unable to map cpupll base\n", np->full_name);
308 		iounmap(gbase);
309 		return;
310 	}
311 
312 	/* overwrite default clock names with DT provided ones */
313 	clk = of_clk_get_by_name(np, clk_names[REFCLK]);
314 	if (!IS_ERR(clk)) {
315 		clk_names[REFCLK] = __clk_get_name(clk);
316 		clk_put(clk);
317 	}
318 
319 	/* simple register PLLs */
320 	clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
321 				   clk_names[SYSPLL], clk_names[REFCLK], 0);
322 	if (IS_ERR(clk))
323 		goto bg2q_fail;
324 
325 	clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
326 				   clk_names[CPUPLL], clk_names[REFCLK], 0);
327 	if (IS_ERR(clk))
328 		goto bg2q_fail;
329 
330 	/* TODO: add BG2Q AVPLL */
331 
332 	/*
333 	 * TODO: add reference clock bypass switches:
334 	 * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass
335 	 */
336 
337 	/* clock divider cells */
338 	for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
339 		const struct berlin2_div_data *dd = &bg2q_divs[n];
340 		int k;
341 
342 		for (k = 0; k < dd->num_parents; k++)
343 			parent_names[k] = clk_names[dd->parent_ids[k]];
344 
345 		clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
346 				dd->name, dd->div_flags, parent_names,
347 				dd->num_parents, dd->flags, &lock);
348 	}
349 
350 	/* clock gate cells */
351 	for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
352 		const struct berlin2_gate_data *gd = &bg2q_gates[n];
353 
354 		clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name,
355 			    gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
356 			    gd->bit_idx, 0, &lock);
357 	}
358 
359 	/*
360 	 * twdclk is derived from cpu/3
361 	 * TODO: use cpupll until cpuclk is not available
362 	 */
363 	clks[CLKID_TWD] =
364 		clk_register_fixed_factor(NULL, "twd", clk_names[CPUPLL],
365 					  0, 1, 3);
366 
367 	/* check for errors on leaf clocks */
368 	for (n = 0; n < MAX_CLKS; n++) {
369 		if (!IS_ERR(clks[n]))
370 			continue;
371 
372 		pr_err("%s: Unable to register leaf clock %d\n",
373 		       np->full_name, n);
374 		goto bg2q_fail;
375 	}
376 
377 	/* register clk-provider */
378 	clk_data.clks = clks;
379 	clk_data.clk_num = MAX_CLKS;
380 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
381 
382 	return;
383 
384 bg2q_fail:
385 	iounmap(cpupll_base);
386 	iounmap(gbase);
387 }
388 CLK_OF_DECLARE(berlin2q_clock, "marvell,berlin2q-chip-ctrl",
389 	       berlin2q_clock_setup);
390