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