]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/clk/berlin/bg2q.c
Merge remote-tracking branch 'mips/mips-for-linux-next'
[karo-tx-linux.git] / drivers / clk / berlin / bg2q.c
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 28
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         { "pcie",       "perif",        22 },
289 };
290
291 static void __init berlin2q_clock_setup(struct device_node *np)
292 {
293         struct device_node *parent_np = of_get_parent(np);
294         const char *parent_names[9];
295         struct clk *clk;
296         int n;
297
298         gbase = of_iomap(parent_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(parent_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         /* cpuclk divider is fixed to 1 */
360         clks[CLKID_CPU] =
361                 clk_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
362                                           0, 1, 1);
363         /* twdclk is derived from cpu/3 */
364         clks[CLKID_TWD] =
365                 clk_register_fixed_factor(NULL, "twd", "cpu", 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_clk, "marvell,berlin2q-clk",
389                berlin2q_clock_setup);