]> Git Repo - J-u-boot.git/blob - drivers/clk/mediatek/clk-mtk.c
rockchip: Avoid #ifdefs in RK3399 SPL
[J-u-boot.git] / drivers / clk / mediatek / clk-mtk.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MediaTek common clock driver
4  *
5  * Copyright (C) 2018 MediaTek Inc.
6  * Author: Ryder Lee <[email protected]>
7  */
8
9 #include <clk-uclass.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <asm/io.h>
13 #include <linux/bitops.h>
14 #include <linux/delay.h>
15
16 #include "clk-mtk.h"
17
18 #define REG_CON0                        0
19 #define REG_CON1                        4
20
21 #define CON0_BASE_EN                    BIT(0)
22 #define CON0_PWR_ON                     BIT(0)
23 #define CON0_ISO_EN                     BIT(1)
24 #define CON1_PCW_CHG                    BIT(31)
25
26 #define POSTDIV_MASK                    0x7
27 #define INTEGER_BITS                    7
28
29 /* scpsys clock off control */
30 #define CLK_SCP_CFG0                    0x200
31 #define CLK_SCP_CFG1                    0x204
32 #define SCP_ARMCK_OFF_EN                GENMASK(9, 0)
33 #define SCP_AXICK_DCM_DIS_EN            BIT(0)
34 #define SCP_AXICK_26M_SEL_EN            BIT(4)
35
36 /* shared functions */
37
38 /*
39  * In case the rate change propagation to parent clocks is undesirable,
40  * this function is recursively called to find the parent to calculate
41  * the accurate frequency.
42  */
43 static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
44                                       struct udevice *pdev)
45 {
46         struct clk parent = { .id = id, };
47
48         if (pdev)
49                 parent.dev = pdev;
50         else
51                 parent.dev = clk->dev;
52
53         return clk_get_rate(&parent);
54 }
55
56 static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
57                                   const struct mtk_composite *mux)
58 {
59         u32 val, index = 0;
60
61         while (mux->parent[index] != parent)
62                 if (++index == mux->num_parents)
63                         return -EINVAL;
64
65         if (mux->flags & CLK_MUX_SETCLR_UPD) {
66                 val = (mux->mux_mask << mux->mux_shift);
67                 writel(val, base + mux->mux_clr_reg);
68
69                 val = (index << mux->mux_shift);
70                 writel(val, base + mux->mux_set_reg);
71
72                 if (mux->upd_shift >= 0)
73                         writel(BIT(mux->upd_shift), base + mux->upd_reg);
74         } else {
75                 /* switch mux to a select parent */
76                 val = readl(base + mux->mux_reg);
77                 val &= ~(mux->mux_mask << mux->mux_shift);
78
79                 val |= index << mux->mux_shift;
80                 writel(val, base + mux->mux_reg);
81         }
82
83         return 0;
84 }
85
86 /* apmixedsys functions */
87
88 static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll,
89                                            u32 fin, u32 pcw, int postdiv)
90 {
91         int pcwbits = pll->pcwbits;
92         int pcwfbits;
93         int ibits;
94         u64 vco;
95         u8 c = 0;
96
97         /* The fractional part of the PLL divider. */
98         ibits = pll->pcwibits ? pll->pcwibits : INTEGER_BITS;
99         pcwfbits = pcwbits > ibits ? pcwbits - ibits : 0;
100
101         vco = (u64)fin * pcw;
102
103         if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
104                 c = 1;
105
106         vco >>= pcwfbits;
107
108         if (c)
109                 vco++;
110
111         return ((unsigned long)vco + postdiv - 1) / postdiv;
112 }
113
114 /**
115  * MediaTek PLLs are configured through their pcw value. The pcw value
116  * describes a divider in the PLL feedback loop which consists of 7 bits
117  * for the integer part and the remaining bits (if present) for the
118  * fractional part. Also they have a 3 bit power-of-two post divider.
119  */
120 static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
121 {
122         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
123         const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
124         u32 val, chg;
125
126         /* set postdiv */
127         val = readl(priv->base + pll->pd_reg);
128         val &= ~(POSTDIV_MASK << pll->pd_shift);
129         val |= (ffs(postdiv) - 1) << pll->pd_shift;
130
131         /* postdiv and pcw need to set at the same time if on same register */
132         if (pll->pd_reg != pll->pcw_reg) {
133                 writel(val, priv->base + pll->pd_reg);
134                 val = readl(priv->base + pll->pcw_reg);
135         }
136
137         /* set pcw */
138         val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift);
139         val |= pcw << pll->pcw_shift;
140
141         if (pll->pcw_chg_reg) {
142                 chg = readl(priv->base + pll->pcw_chg_reg);
143                 chg |= CON1_PCW_CHG;
144                 writel(val, priv->base + pll->pcw_reg);
145                 writel(chg, priv->base + pll->pcw_chg_reg);
146         } else {
147                 val |= CON1_PCW_CHG;
148                 writel(val, priv->base + pll->pcw_reg);
149         }
150
151         udelay(20);
152 }
153
154 /**
155  * mtk_pll_calc_values - calculate good values for a given input frequency.
156  * @clk:        The clk
157  * @pcw:        The pcw value (output)
158  * @postdiv:    The post divider (output)
159  * @freq:       The desired target frequency
160  */
161 static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
162                                 u32 freq)
163 {
164         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
165         const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
166         unsigned long fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
167         u64 _pcw;
168         int ibits;
169         u32 val;
170
171         if (freq > pll->fmax)
172                 freq = pll->fmax;
173
174         for (val = 0; val < 5; val++) {
175                 *postdiv = 1 << val;
176                 if ((u64)freq * *postdiv >= fmin)
177                         break;
178         }
179
180         /* _pcw = freq * postdiv / xtal_rate * 2^pcwfbits */
181         ibits = pll->pcwibits ? pll->pcwibits : INTEGER_BITS;
182         _pcw = ((u64)freq << val) << (pll->pcwbits - ibits);
183         do_div(_pcw, priv->tree->xtal2_rate);
184
185         *pcw = (u32)_pcw;
186 }
187
188 static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
189 {
190         u32 pcw = 0;
191         u32 postdiv;
192
193         mtk_pll_calc_values(clk, &pcw, &postdiv, rate);
194         mtk_pll_set_rate_regs(clk, pcw, postdiv);
195
196         return 0;
197 }
198
199 static ulong mtk_apmixedsys_get_rate(struct clk *clk)
200 {
201         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
202         const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
203         u32 postdiv;
204         u32 pcw;
205
206         postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) &
207                    POSTDIV_MASK;
208         postdiv = 1 << postdiv;
209
210         pcw = readl(priv->base + pll->pcw_reg) >> pll->pcw_shift;
211         pcw &= GENMASK(pll->pcwbits - 1, 0);
212
213         return __mtk_pll_recalc_rate(pll, priv->tree->xtal2_rate,
214                                      pcw, postdiv);
215 }
216
217 static int mtk_apmixedsys_enable(struct clk *clk)
218 {
219         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
220         const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
221         u32 r;
222
223         r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON;
224         writel(r, priv->base + pll->pwr_reg);
225         udelay(1);
226
227         r = readl(priv->base + pll->pwr_reg) & ~CON0_ISO_EN;
228         writel(r, priv->base + pll->pwr_reg);
229         udelay(1);
230
231         r = readl(priv->base + pll->reg + REG_CON0);
232         r |= pll->en_mask;
233         writel(r, priv->base + pll->reg + REG_CON0);
234
235         udelay(20);
236
237         if (pll->flags & HAVE_RST_BAR) {
238                 r = readl(priv->base + pll->reg + REG_CON0);
239                 r |= pll->rst_bar_mask;
240                 writel(r, priv->base + pll->reg + REG_CON0);
241         }
242
243         return 0;
244 }
245
246 static int mtk_apmixedsys_disable(struct clk *clk)
247 {
248         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
249         const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
250         u32 r;
251
252         if (pll->flags & HAVE_RST_BAR) {
253                 r = readl(priv->base + pll->reg + REG_CON0);
254                 r &= ~pll->rst_bar_mask;
255                 writel(r, priv->base + pll->reg + REG_CON0);
256         }
257
258         r = readl(priv->base + pll->reg + REG_CON0);
259         r &= ~CON0_BASE_EN;
260         writel(r, priv->base + pll->reg + REG_CON0);
261
262         r = readl(priv->base + pll->pwr_reg) | CON0_ISO_EN;
263         writel(r, priv->base + pll->pwr_reg);
264
265         r = readl(priv->base + pll->pwr_reg) & ~CON0_PWR_ON;
266         writel(r, priv->base + pll->pwr_reg);
267
268         return 0;
269 }
270
271 /* topckgen functions */
272
273 static ulong mtk_factor_recalc_rate(const struct mtk_fixed_factor *fdiv,
274                                     ulong parent_rate)
275 {
276         u64 rate = parent_rate * fdiv->mult;
277
278         do_div(rate, fdiv->div);
279
280         return rate;
281 }
282
283 static ulong mtk_topckgen_get_factor_rate(struct clk *clk, u32 off)
284 {
285         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
286         const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off];
287         ulong rate;
288
289         switch (fdiv->flags & CLK_PARENT_MASK) {
290         case CLK_PARENT_APMIXED:
291                 rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
292                                                 priv->parent);
293                 break;
294         case CLK_PARENT_TOPCKGEN:
295                 rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
296                 break;
297
298         case CLK_PARENT_XTAL:
299         default:
300                 rate = priv->tree->xtal_rate;
301         }
302
303         return mtk_factor_recalc_rate(fdiv, rate);
304 }
305
306 static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off)
307 {
308         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
309         const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off];
310         ulong rate;
311
312         switch (fdiv->flags & CLK_PARENT_MASK) {
313         case CLK_PARENT_TOPCKGEN:
314                 rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
315                                                 priv->parent);
316                 break;
317         case CLK_PARENT_XTAL:
318                 rate = priv->tree->xtal_rate;
319                 break;
320         default:
321                 rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
322         }
323
324         return mtk_factor_recalc_rate(fdiv, rate);
325 }
326
327 static ulong mtk_topckgen_get_mux_rate(struct clk *clk, u32 off)
328 {
329         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
330         const struct mtk_composite *mux = &priv->tree->muxes[off];
331         u32 index;
332
333         index = readl(priv->base + mux->mux_reg);
334         index &= mux->mux_mask << mux->mux_shift;
335         index = index >> mux->mux_shift;
336
337         if (mux->parent[index] > 0 ||
338             (mux->parent[index] == CLK_XTAL &&
339              priv->tree->flags & CLK_BYPASS_XTAL)) {
340                 switch (mux->flags & CLK_PARENT_MASK) {
341                 case CLK_PARENT_APMIXED:
342                         return mtk_clk_find_parent_rate(clk, mux->parent[index],
343                                                         priv->parent);
344                         break;
345                 default:
346                         return mtk_clk_find_parent_rate(clk, mux->parent[index],
347                                                         NULL);
348                         break;
349                 }
350         }
351
352         return priv->tree->xtal_rate;
353 }
354
355 static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
356 {
357         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
358         const struct mtk_composite *mux = &priv->tree->muxes[off];
359         u32 index;
360
361         index = readl(priv->base + mux->mux_reg);
362         index &= mux->mux_mask << mux->mux_shift;
363         index = index >> mux->mux_shift;
364
365         if (mux->parent[index] > 0 ||
366             (mux->parent[index] == CLK_XTAL &&
367              priv->tree->flags & CLK_BYPASS_XTAL)) {
368                 switch (mux->flags & CLK_PARENT_MASK) {
369                 case CLK_PARENT_TOPCKGEN:
370                         return mtk_clk_find_parent_rate(clk, mux->parent[index],
371                                                         priv->parent);
372                         break;
373                 default:
374                         return mtk_clk_find_parent_rate(clk, mux->parent[index],
375                                                         NULL);
376                         break;
377                 }
378         }
379         return 0;
380 }
381
382 static ulong mtk_topckgen_get_rate(struct clk *clk)
383 {
384         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
385
386         if (clk->id < priv->tree->fdivs_offs)
387                 return priv->tree->fclks[clk->id].rate;
388         else if (clk->id < priv->tree->muxes_offs)
389                 return mtk_topckgen_get_factor_rate(clk, clk->id -
390                                                     priv->tree->fdivs_offs);
391         else
392                 return mtk_topckgen_get_mux_rate(clk, clk->id -
393                                                  priv->tree->muxes_offs);
394 }
395
396 static ulong mtk_infrasys_get_rate(struct clk *clk)
397 {
398         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
399
400         ulong rate;
401
402         if (clk->id < priv->tree->fdivs_offs) {
403                 rate = priv->tree->fclks[clk->id].rate;
404         } else if (clk->id < priv->tree->muxes_offs) {
405                 rate = mtk_infrasys_get_factor_rate(clk, clk->id -
406                                                     priv->tree->fdivs_offs);
407         } else {
408                 rate = mtk_infrasys_get_mux_rate(clk, clk->id -
409                                                  priv->tree->muxes_offs);
410         }
411
412         return rate;
413 }
414
415 static int mtk_clk_mux_enable(struct clk *clk)
416 {
417         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
418         const struct mtk_composite *mux;
419         u32 val;
420
421         if (clk->id < priv->tree->muxes_offs)
422                 return 0;
423
424         mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
425         if (mux->gate_shift < 0)
426                 return 0;
427
428         /* enable clock gate */
429         if (mux->flags & CLK_MUX_SETCLR_UPD) {
430                 val = BIT(mux->gate_shift);
431                 writel(val, priv->base + mux->mux_clr_reg);
432         } else {
433                 val = readl(priv->base + mux->gate_reg);
434                 val &= ~BIT(mux->gate_shift);
435                 writel(val, priv->base + mux->gate_reg);
436         }
437
438         if (mux->flags & CLK_DOMAIN_SCPSYS) {
439                 /* enable scpsys clock off control */
440                 writel(SCP_ARMCK_OFF_EN, priv->base + CLK_SCP_CFG0);
441                 writel(SCP_AXICK_DCM_DIS_EN | SCP_AXICK_26M_SEL_EN,
442                        priv->base + CLK_SCP_CFG1);
443         }
444
445         return 0;
446 }
447
448 static int mtk_clk_mux_disable(struct clk *clk)
449 {
450         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
451         const struct mtk_composite *mux;
452         u32 val;
453
454         if (clk->id < priv->tree->muxes_offs)
455                 return 0;
456
457         mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
458         if (mux->gate_shift < 0)
459                 return 0;
460
461         /* disable clock gate */
462         if (mux->flags & CLK_MUX_SETCLR_UPD) {
463                 val = BIT(mux->gate_shift);
464                 writel(val, priv->base + mux->mux_set_reg);
465         } else {
466                 val = readl(priv->base + mux->gate_reg);
467                 val |= BIT(mux->gate_shift);
468                 writel(val, priv->base + mux->gate_reg);
469         }
470
471         return 0;
472 }
473
474 static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
475 {
476         struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
477
478         if (clk->id < priv->tree->muxes_offs)
479                 return 0;
480
481         return mtk_clk_mux_set_parent(priv->base, parent->id,
482                         &priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
483 }
484
485 /* CG functions */
486
487 static int mtk_clk_gate_enable(struct clk *clk)
488 {
489         struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
490         const struct mtk_gate *gate = &priv->gates[clk->id];
491         u32 bit = BIT(gate->shift);
492
493         switch (gate->flags & CLK_GATE_MASK) {
494         case CLK_GATE_SETCLR:
495                 writel(bit, priv->base + gate->regs->clr_ofs);
496                 break;
497         case CLK_GATE_SETCLR_INV:
498                 writel(bit, priv->base + gate->regs->set_ofs);
499                 break;
500         case CLK_GATE_NO_SETCLR:
501                 clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
502                 break;
503         case CLK_GATE_NO_SETCLR_INV:
504                 clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
505                 break;
506
507         default:
508                 return -EINVAL;
509         }
510
511         return 0;
512 }
513
514 static int mtk_clk_gate_disable(struct clk *clk)
515 {
516         struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
517         const struct mtk_gate *gate = &priv->gates[clk->id];
518         u32 bit = BIT(gate->shift);
519
520         switch (gate->flags & CLK_GATE_MASK) {
521         case CLK_GATE_SETCLR:
522                 writel(bit, priv->base + gate->regs->set_ofs);
523                 break;
524         case CLK_GATE_SETCLR_INV:
525                 writel(bit, priv->base + gate->regs->clr_ofs);
526                 break;
527         case CLK_GATE_NO_SETCLR:
528                 clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
529                 break;
530         case CLK_GATE_NO_SETCLR_INV:
531                 clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
532                 break;
533
534         default:
535                 return -EINVAL;
536         }
537
538         return 0;
539 }
540
541 static ulong mtk_clk_gate_get_rate(struct clk *clk)
542 {
543         struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
544         const struct mtk_gate *gate = &priv->gates[clk->id];
545
546         return mtk_clk_find_parent_rate(clk, gate->parent, priv->parent);
547 }
548
549 const struct clk_ops mtk_clk_apmixedsys_ops = {
550         .enable = mtk_apmixedsys_enable,
551         .disable = mtk_apmixedsys_disable,
552         .set_rate = mtk_apmixedsys_set_rate,
553         .get_rate = mtk_apmixedsys_get_rate,
554 };
555
556 const struct clk_ops mtk_clk_topckgen_ops = {
557         .enable = mtk_clk_mux_enable,
558         .disable = mtk_clk_mux_disable,
559         .get_rate = mtk_topckgen_get_rate,
560         .set_parent = mtk_common_clk_set_parent,
561 };
562
563 const struct clk_ops mtk_clk_infrasys_ops = {
564         .enable = mtk_clk_mux_enable,
565         .disable = mtk_clk_mux_disable,
566         .get_rate = mtk_infrasys_get_rate,
567         .set_parent = mtk_common_clk_set_parent,
568 };
569
570 const struct clk_ops mtk_clk_gate_ops = {
571         .enable = mtk_clk_gate_enable,
572         .disable = mtk_clk_gate_disable,
573         .get_rate = mtk_clk_gate_get_rate,
574 };
575
576 int mtk_common_clk_init(struct udevice *dev,
577                         const struct mtk_clk_tree *tree)
578 {
579         struct mtk_clk_priv *priv = dev_get_priv(dev);
580         struct udevice *parent;
581         int ret;
582
583         priv->base = dev_read_addr_ptr(dev);
584         if (!priv->base)
585                 return -ENOENT;
586
587         ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
588         if (ret || !parent) {
589                 ret = uclass_get_device_by_driver(UCLASS_CLK,
590                                 DM_DRIVER_GET(mtk_clk_apmixedsys), &parent);
591                 if (ret || !parent)
592                         return -ENOENT;
593         }
594
595         priv->parent = parent;
596         priv->tree = tree;
597
598         return 0;
599 }
600
601 int mtk_common_clk_gate_init(struct udevice *dev,
602                              const struct mtk_clk_tree *tree,
603                              const struct mtk_gate *gates)
604 {
605         struct mtk_cg_priv *priv = dev_get_priv(dev);
606         struct udevice *parent;
607         int ret;
608
609         priv->base = dev_read_addr_ptr(dev);
610         if (!priv->base)
611                 return -ENOENT;
612
613         ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
614         if (ret || !parent) {
615                 ret = uclass_get_device_by_driver(UCLASS_CLK,
616                                 DM_DRIVER_GET(mtk_clk_topckgen), &parent);
617                 if (ret || !parent)
618                         return -ENOENT;
619         }
620
621         priv->parent = parent;
622         priv->tree = tree;
623         priv->gates = gates;
624
625         return 0;
626 }
This page took 0.065492 seconds and 4 git commands to generate.