mxs_nand: Add support for i.MX8M
[oweals/u-boot.git] / drivers / clk / mvebu / armada-37xx-periph.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Marvell Armada 37xx SoC Peripheral clocks
4  *
5  * Marek Behun <marek.behun@nic.cz>
6  *
7  * Based on Linux driver by:
8  *   Gregory CLEMENT <gregory.clement@free-electrons.com>
9  */
10
11 #include <common.h>
12 #include <malloc.h>
13 #include <clk-uclass.h>
14 #include <clk.h>
15 #include <dm.h>
16 #include <asm/io.h>
17 #include <asm/arch/cpu.h>
18 #include <dm/device_compat.h>
19
20 #define TBG_SEL         0x0
21 #define DIV_SEL0        0x4
22 #define DIV_SEL1        0x8
23 #define DIV_SEL2        0xC
24 #define CLK_SEL         0x10
25 #define CLK_DIS         0x14
26
27 enum a37xx_periph_parent {
28         TBG_A_P         = 0,
29         TBG_B_P         = 1,
30         TBG_A_S         = 2,
31         TBG_B_S         = 3,
32         MAX_TBG_PARENTS = 4,
33         XTAL            = 4,
34         MAX_PARENTS     = 5,
35 };
36
37 static const struct {
38         const char *name;
39         enum a37xx_periph_parent parent;
40 } a37xx_periph_parent_names[] = {
41         { "TBG-A-P", TBG_A_P },
42         { "TBG-B-P", TBG_B_P },
43         { "TBG-A-S", TBG_A_S },
44         { "TBG-B-S", TBG_B_S },
45         { "xtal",    XTAL    },
46 };
47
48 struct clk_periph;
49
50 struct a37xx_periphclk {
51         void __iomem *reg;
52
53         ulong parents[MAX_PARENTS];
54
55         const struct clk_periph *clks;
56         bool clk_has_periph_parent[16];
57         int clk_parent[16];
58
59         int count;
60 };
61
62 struct clk_div_table {
63         u32 div;
64         u32 val;
65 };
66
67 struct clk_periph {
68         const char *name;
69
70         const char *parent_name;
71
72         u32 disable_bit;
73         int mux_shift;
74
75         const struct clk_div_table *div_table[2];
76         s32 div_reg_off[2];
77         u32 div_mask[2];
78         int div_shift[2];
79
80         unsigned can_gate : 1;
81         unsigned can_mux : 1;
82         unsigned dividers : 2;
83 };
84
85 static const struct clk_div_table div_table1[] = {
86         { 1, 1 },
87         { 2, 2 },
88         { 0, 0 },
89 };
90
91 static const struct clk_div_table div_table2[] = {
92         { 2, 0 },
93         { 4, 1 },
94         { 0, 0 },
95 };
96
97 static const struct clk_div_table div_table6[] = {
98         { 1, 1 },
99         { 2, 2 },
100         { 3, 3 },
101         { 4, 4 },
102         { 5, 5 },
103         { 6, 6 },
104         { 0, 0 },
105 };
106
107 #define CLK_FULL_DD(_n, _d, _mux, _r0, _r1, _s0, _s1)   \
108         {                                               \
109                 .name = #_n,                            \
110                 .disable_bit = BIT(_d),                 \
111                 .mux_shift = _mux,                      \
112                 .div_table[0] = div_table6,             \
113                 .div_table[1] = div_table6,             \
114                 .div_reg_off[0] = _r0,                  \
115                 .div_reg_off[1] = _r1,                  \
116                 .div_shift[0] = _s0,                    \
117                 .div_shift[1] = _s1,                    \
118                 .div_mask[0] = 7,                       \
119                 .div_mask[1] = 7,                       \
120                 .can_gate = 1,                          \
121                 .can_mux = 1,                           \
122                 .dividers = 2,                          \
123         }
124
125 #define CLK_FULL(_n, _d, _mux, _r, _s, _m, _t)  \
126         {                                       \
127                 .name = #_n,                    \
128                 .disable_bit = BIT(_d),         \
129                 .mux_shift = _mux,              \
130                 .div_table[0] = _t,             \
131                 .div_reg_off[0] = _r,           \
132                 .div_shift[0] = _s,             \
133                 .div_mask[0] = _m,              \
134                 .can_gate = 1,                  \
135                 .can_mux = 1,                   \
136                 .dividers = 1,                  \
137         }
138
139 #define CLK_GATE_DIV(_n, _d, _r, _s, _m, _t, _p)        \
140         {                                               \
141                 .name = #_n,                            \
142                 .parent_name = _p,                      \
143                 .disable_bit = BIT(_d),                 \
144                 .div_table[0] = _t,                     \
145                 .div_reg_off[0] = _r,                   \
146                 .div_shift[0] = _s,                     \
147                 .div_mask[0] = _m,                      \
148                 .can_gate = 1,                          \
149                 .dividers = 1,                          \
150         }
151
152 #define CLK_GATE(_n, _d, _p)            \
153         {                               \
154                 .name = #_n,            \
155                 .parent_name = _p,      \
156                 .disable_bit = BIT(_d), \
157                 .can_gate = 1,          \
158         }
159
160 #define CLK_MUX_DIV(_n, _mux, _r, _s, _m, _t)   \
161         {                                       \
162                 .name = #_n,                    \
163                 .mux_shift = _mux,              \
164                 .div_table[0] = _t,             \
165                 .div_reg_off[0] = _r,           \
166                 .div_shift[0] = _s,             \
167                 .div_mask[0] = _m,              \
168                 .can_mux = 1,                   \
169                 .dividers = 1,                  \
170         }
171
172 #define CLK_MUX_DD(_n, _mux, _r0, _r1, _s0, _s1)        \
173         {                                               \
174                 .name = #_n,                            \
175                 .mux_shift = _mux,                      \
176                 .div_table[0] = div_table6,             \
177                 .div_table[1] = div_table6,             \
178                 .div_reg_off[0] = _r0,                  \
179                 .div_reg_off[1] = _r1,                  \
180                 .div_shift[0] = _s0,                    \
181                 .div_shift[1] = _s1,                    \
182                 .div_mask[0] = 7,                       \
183                 .div_mask[1] = 7,                       \
184                 .can_mux = 1,                           \
185                 .dividers = 2,                          \
186         }
187
188 /* NB periph clocks */
189 static const struct clk_periph clks_nb[] = {
190         CLK_FULL_DD(mmc, 2, 0, DIV_SEL2, DIV_SEL2, 16, 13),
191         CLK_FULL_DD(sata_host, 3, 2, DIV_SEL2, DIV_SEL2, 10, 7),
192         CLK_FULL_DD(sec_at, 6, 4, DIV_SEL1, DIV_SEL1, 3, 0),
193         CLK_FULL_DD(sec_dap, 7, 6, DIV_SEL1, DIV_SEL1, 9, 6),
194         CLK_FULL_DD(tscem, 8, 8, DIV_SEL1, DIV_SEL1, 15, 12),
195         CLK_FULL(tscem_tmx, 10, 10, DIV_SEL1, 18, 7, div_table6),
196         CLK_GATE(avs, 11, "xtal"),
197         CLK_FULL_DD(sqf, 12, 12, DIV_SEL1, DIV_SEL1, 27, 24),
198         CLK_FULL_DD(pwm, 13, 14, DIV_SEL0, DIV_SEL0, 3, 0),
199         CLK_GATE(i2c_2, 16, "xtal"),
200         CLK_GATE(i2c_1, 17, "xtal"),
201         CLK_GATE_DIV(ddr_phy, 19, DIV_SEL0, 18, 1, div_table2, "TBG-A-S"),
202         CLK_FULL_DD(ddr_fclk, 21, 16, DIV_SEL0, DIV_SEL0, 15, 12),
203         CLK_FULL(trace, 22, 18, DIV_SEL0, 20, 7, div_table6),
204         CLK_FULL(counter, 23, 20, DIV_SEL0, 23, 7, div_table6),
205         CLK_FULL_DD(eip97, 24, 24, DIV_SEL2, DIV_SEL2, 22, 19),
206         CLK_MUX_DIV(cpu, 22, DIV_SEL0, 28, 7, div_table6),
207         { },
208 };
209
210 /* SB periph clocks */
211 static const struct clk_periph clks_sb[] = {
212         CLK_MUX_DD(gbe_50, 6, DIV_SEL2, DIV_SEL2, 6, 9),
213         CLK_MUX_DD(gbe_core, 8, DIV_SEL1, DIV_SEL1, 18, 21),
214         CLK_MUX_DD(gbe_125, 10, DIV_SEL1, DIV_SEL1, 6, 9),
215         CLK_GATE(gbe1_50, 0, "gbe_50"),
216         CLK_GATE(gbe0_50, 1, "gbe_50"),
217         CLK_GATE(gbe1_125, 2, "gbe_125"),
218         CLK_GATE(gbe0_125, 3, "gbe_125"),
219         CLK_GATE_DIV(gbe1_core, 4, DIV_SEL1, 13, 1, div_table1, "gbe_core"),
220         CLK_GATE_DIV(gbe0_core, 5, DIV_SEL1, 14, 1, div_table1, "gbe_core"),
221         CLK_GATE_DIV(gbe_bm, 12, DIV_SEL1, 0, 1, div_table1, "gbe_core"),
222         CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6),
223         CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12),
224         CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18),
225         { },
226 };
227
228 static int get_mux(struct a37xx_periphclk *priv, int shift)
229 {
230         return (readl(priv->reg + TBG_SEL) >> shift) & 3;
231 }
232
233 static void set_mux(struct a37xx_periphclk *priv, int shift, int val)
234 {
235         u32 reg;
236
237         reg = readl(priv->reg + TBG_SEL);
238         reg &= ~(3 << shift);
239         reg |= (val & 3) << shift;
240         writel(reg, priv->reg + TBG_SEL);
241 }
242
243 static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id);
244
245 static ulong get_parent_rate(struct a37xx_periphclk *priv, int id)
246 {
247         const struct clk_periph *clk = &priv->clks[id];
248         ulong res;
249
250         if (clk->can_mux) {
251                 /* parent is one of TBG clocks */
252                 int tbg = get_mux(priv, clk->mux_shift);
253
254                 res = priv->parents[tbg];
255         } else if (priv->clk_has_periph_parent[id]) {
256                 /* parent is one of other periph clocks */
257
258                 if (priv->clk_parent[id] >= priv->count)
259                         return -EINVAL;
260
261                 res = periph_clk_get_rate(priv, priv->clk_parent[id]);
262         } else {
263                 /* otherwise parent is one of TBGs or XTAL */
264
265                 if (priv->clk_parent[id] >= MAX_PARENTS)
266                         return -EINVAL;
267
268                 res = priv->parents[priv->clk_parent[id]];
269         }
270
271         return res;
272 }
273
274 static ulong get_div(struct a37xx_periphclk *priv,
275                      const struct clk_periph *clk, int idx)
276 {
277         const struct clk_div_table *i;
278         u32 reg;
279
280         reg = readl(priv->reg + clk->div_reg_off[idx]);
281         reg = (reg >> clk->div_shift[idx]) & clk->div_mask[idx];
282
283         /* find divisor for register value val */
284         for (i = clk->div_table[idx]; i && i->div != 0; ++i)
285                 if (i->val == reg)
286                         return i->div;
287
288         return 0;
289 }
290
291 static void set_div_val(struct a37xx_periphclk *priv,
292                         const struct clk_periph *clk, int idx, int val)
293 {
294         u32 reg;
295
296         reg = readl(priv->reg + clk->div_reg_off[idx]);
297         reg &= ~(clk->div_mask[idx] << clk->div_shift[idx]);
298         reg |= (val & clk->div_mask[idx]) << clk->div_shift[idx];
299         writel(reg, priv->reg + clk->div_reg_off[idx]);
300 }
301
302 static ulong periph_clk_get_rate(struct a37xx_periphclk *priv, int id)
303 {
304         const struct clk_periph *clk = &priv->clks[id];
305         ulong rate, div;
306         int i;
307
308         rate = get_parent_rate(priv, id);
309         if (rate == -EINVAL)
310                 return -EINVAL;
311
312         /* divide the parent rate by dividers */
313         div = 1;
314         for (i = 0; i < clk->dividers; ++i)
315                 div *= get_div(priv, clk, i);
316
317         if (!div)
318                 return 0;
319
320         return DIV_ROUND_UP(rate, div);
321 }
322
323 static ulong armada_37xx_periph_clk_get_rate(struct clk *clk)
324 {
325         struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
326
327         if (clk->id >= priv->count)
328                 return -EINVAL;
329
330         return periph_clk_get_rate(priv, clk->id);
331 }
332
333 static int periph_clk_enable(struct clk *clk, int enable)
334 {
335         struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
336         const struct clk_periph *periph_clk = &priv->clks[clk->id];
337
338         if (clk->id >= priv->count)
339                 return -EINVAL;
340
341         if (!periph_clk->can_gate)
342                 return -ENOTSUPP;
343
344         if (enable)
345                 clrbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
346         else
347                 setbits_le32(priv->reg + CLK_DIS, periph_clk->disable_bit);
348
349         return 0;
350 }
351
352 static int armada_37xx_periph_clk_enable(struct clk *clk)
353 {
354         return periph_clk_enable(clk, 1);
355 }
356
357 static int armada_37xx_periph_clk_disable(struct clk *clk)
358 {
359         return periph_clk_enable(clk, 0);
360 }
361
362 #define diff(a, b) abs((long)(a) - (long)(b))
363
364 static ulong find_best_div(const struct clk_div_table *t0,
365                            const struct clk_div_table *t1, ulong parent_rate,
366                            ulong req_rate, int *v0, int *v1)
367 {
368         const struct clk_div_table *i, *j;
369         ulong rate, best_rate = 0;
370
371         for (i = t0; i && i->div; ++i) {
372                 for (j = t1; j && j->div; ++j) {
373                         rate = DIV_ROUND_UP(parent_rate, i->div * j->div);
374
375                         if (!best_rate ||
376                             diff(rate, req_rate) < diff(best_rate, req_rate)) {
377                                 best_rate = rate;
378                                 *v0 = i->val;
379                                 *v1 = j->val;
380                         }
381                 }
382         }
383
384         return best_rate;
385 }
386
387 static ulong armada_37xx_periph_clk_set_rate(struct clk *clk, ulong req_rate)
388 {
389         struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
390         const struct clk_periph *periph_clk = &priv->clks[clk->id];
391         ulong rate, old_rate, parent_rate;
392         int div_val0 = 0, div_val1 = 0;
393         const struct clk_div_table *t1;
394         static const struct clk_div_table empty_table[2] = {
395                 { 1, 0 },
396                 { 0, 0 }
397         };
398
399         if (clk->id > priv->count)
400                 return -EINVAL;
401
402         old_rate = periph_clk_get_rate(priv, clk->id);
403         if (old_rate == -EINVAL)
404                 return -EINVAL;
405
406         if (old_rate == req_rate)
407                 return old_rate;
408
409         if (!periph_clk->can_gate || !periph_clk->dividers)
410                 return -ENOTSUPP;
411
412         parent_rate = get_parent_rate(priv, clk->id);
413         if (parent_rate == -EINVAL)
414                 return -EINVAL;
415
416         t1 = empty_table;
417         if (periph_clk->dividers > 1)
418                 t1 = periph_clk->div_table[1];
419
420         rate = find_best_div(periph_clk->div_table[0], t1, parent_rate,
421                              req_rate, &div_val0, &div_val1);
422
423         periph_clk_enable(clk, 0);
424
425         set_div_val(priv, periph_clk, 0, div_val0);
426         if (periph_clk->dividers > 1)
427                 set_div_val(priv, periph_clk, 1, div_val1);
428
429         periph_clk_enable(clk, 1);
430
431         return rate;
432 }
433
434 static int armada_37xx_periph_clk_set_parent(struct clk *clk,
435                                              struct clk *parent)
436 {
437         struct a37xx_periphclk *priv = dev_get_priv(clk->dev);
438         const struct clk_periph *periph_clk = &priv->clks[clk->id];
439         struct clk check_parent;
440         int ret;
441
442         /* We also check if parent is our TBG clock */
443         if (clk->id > priv->count || parent->id >= MAX_TBG_PARENTS)
444                 return -EINVAL;
445
446         if (!periph_clk->can_mux || !periph_clk->can_gate)
447                 return -ENOTSUPP;
448
449         ret = clk_get_by_index(clk->dev, 0, &check_parent);
450         if (ret < 0)
451                 return ret;
452
453         if (parent->dev != check_parent.dev)
454                 ret = -EINVAL;
455
456         clk_free(&check_parent);
457         if (ret < 0)
458                 return ret;
459
460         periph_clk_enable(clk, 0);
461         set_mux(priv, periph_clk->mux_shift, parent->id);
462         periph_clk_enable(clk, 1);
463
464         return 0;
465 }
466
467 #if defined(CONFIG_CMD_CLK) && defined(CONFIG_CLK_ARMADA_3720)
468 static int armada_37xx_periph_clk_dump(struct udevice *dev)
469 {
470         struct a37xx_periphclk *priv = dev_get_priv(dev);
471         const struct clk_periph *clks;
472         int i;
473
474         if (!priv)
475                 return -ENODEV;
476
477         clks = priv->clks;
478
479         for (i = 0; i < priv->count; ++i)
480                 printf("  %s at %lu Hz\n", clks[i].name,
481                        periph_clk_get_rate(priv, i));
482         printf("\n");
483
484         return 0;
485 }
486
487 static int clk_dump(const char *name, int (*func)(struct udevice *))
488 {
489         struct udevice *dev;
490
491         if (uclass_get_device_by_name(UCLASS_CLK, name, &dev)) {
492                 printf("Cannot find device %s\n", name);
493                 return -ENODEV;
494         }
495
496         return func(dev);
497 }
498
499 int armada_37xx_tbg_clk_dump(struct udevice *);
500
501 int soc_clk_dump(void)
502 {
503         printf("  xtal at %u000000 Hz\n\n", get_ref_clk());
504
505         if (clk_dump("tbg@13200", armada_37xx_tbg_clk_dump))
506                 return 1;
507
508         if (clk_dump("nb-periph-clk@13000",
509                      armada_37xx_periph_clk_dump))
510                 return 1;
511
512         if (clk_dump("sb-periph-clk@18000",
513                      armada_37xx_periph_clk_dump))
514                 return 1;
515
516         return 0;
517 }
518 #endif
519
520 static int armada_37xx_periph_clk_probe(struct udevice *dev)
521 {
522         struct a37xx_periphclk *priv = dev_get_priv(dev);
523         const struct clk_periph *clks;
524         int ret, i;
525
526         clks = (const struct clk_periph *)dev_get_driver_data(dev);
527         if (!clks)
528                 return -ENODEV;
529
530         priv->reg = dev_read_addr_ptr(dev);
531         if (!priv->reg) {
532                 dev_err(dev, "no io address\n");
533                 return -ENODEV;
534         }
535
536         /* count clk_periph nodes */
537         priv->count = 0;
538         while (clks[priv->count].name)
539                 priv->count++;
540
541         priv->clks = clks;
542
543         /* assign parent IDs to nodes which have non-NULL parent_name */
544         for (i = 0; i < priv->count; ++i) {
545                 int j;
546
547                 if (!clks[i].parent_name)
548                         continue;
549
550                 /* first try if parent_name is one of TBGs or XTAL */
551                 for (j = 0; j < MAX_PARENTS; ++j)
552                         if (!strcmp(clks[i].parent_name,
553                                     a37xx_periph_parent_names[j].name))
554                                 break;
555
556                 if (j < MAX_PARENTS) {
557                         priv->clk_has_periph_parent[i] = false;
558                         priv->clk_parent[i] =
559                                 a37xx_periph_parent_names[j].parent;
560                         continue;
561                 }
562
563                 /* else parent_name should be one of other periph clocks */
564                 for (j = 0; j < priv->count; ++j) {
565                         if (!strcmp(clks[i].parent_name, clks[j].name))
566                                 break;
567                 }
568
569                 if (j < priv->count) {
570                         priv->clk_has_periph_parent[i] = true;
571                         priv->clk_parent[i] = j;
572                         continue;
573                 }
574
575                 dev_err(dev, "undefined parent %s\n", clks[i].parent_name);
576                 return -EINVAL;
577         }
578
579         for (i = 0; i < MAX_PARENTS; ++i) {
580                 struct clk clk;
581
582                 if (i == XTAL) {
583                         priv->parents[i] = get_ref_clk() * 1000000;
584                         continue;
585                 }
586
587                 ret = clk_get_by_index(dev, i, &clk);
588                 if (ret) {
589                         dev_err(dev, "one of parent clocks (%i) missing: %i\n",
590                                 i, ret);
591                         return -ENODEV;
592                 }
593
594                 priv->parents[i] = clk_get_rate(&clk);
595                 clk_free(&clk);
596         }
597
598         return 0;
599 }
600
601 static const struct clk_ops armada_37xx_periph_clk_ops = {
602         .get_rate = armada_37xx_periph_clk_get_rate,
603         .set_rate = armada_37xx_periph_clk_set_rate,
604         .set_parent = armada_37xx_periph_clk_set_parent,
605         .enable = armada_37xx_periph_clk_enable,
606         .disable = armada_37xx_periph_clk_disable,
607 };
608
609 static const struct udevice_id armada_37xx_periph_clk_ids[] = {
610         {
611                 .compatible = "marvell,armada-3700-periph-clock-nb",
612                 .data = (ulong)clks_nb,
613         },
614         {
615                 .compatible = "marvell,armada-3700-periph-clock-sb",
616                 .data = (ulong)clks_sb,
617         },
618         {}
619 };
620
621 U_BOOT_DRIVER(armada_37xx_periph_clk) = {
622         .name           = "armada_37xx_periph_clk",
623         .id             = UCLASS_CLK,
624         .of_match       = armada_37xx_periph_clk_ids,
625         .ops            = &armada_37xx_periph_clk_ops,
626         .priv_auto_alloc_size = sizeof(struct a37xx_periphclk),
627         .probe          = armada_37xx_periph_clk_probe,
628 };