blob: 592f8062e595220e50acef543e4a1ec77a29e466 [file] [log] [blame]
developer2186c982018-11-15 10:07:54 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * MediaTek common clock driver
4 *
5 * Copyright (C) 2018 MediaTek Inc.
6 * Author: Ryder Lee <ryder.lee@mediatek.com>
7 */
8
Tom Riniabb9a042024-05-18 20:20:43 -06009#include <common.h>
developer2186c982018-11-15 10:07:54 +080010#include <clk-uclass.h>
11#include <div64.h>
12#include <dm.h>
13#include <asm/io.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
developer2186c982018-11-15 10:07:54 +080016
17#include "clk-mtk.h"
18
19#define REG_CON0 0
20#define REG_CON1 4
21
22#define CON0_BASE_EN BIT(0)
23#define CON0_PWR_ON BIT(0)
24#define CON0_ISO_EN BIT(1)
25#define CON1_PCW_CHG BIT(31)
26
27#define POSTDIV_MASK 0x7
28#define INTEGER_BITS 7
29
30/* scpsys clock off control */
31#define CLK_SCP_CFG0 0x200
32#define CLK_SCP_CFG1 0x204
33#define SCP_ARMCK_OFF_EN GENMASK(9, 0)
34#define SCP_AXICK_DCM_DIS_EN BIT(0)
35#define SCP_AXICK_26M_SEL_EN BIT(4)
36
37/* shared functions */
38
39/*
40 * In case the rate change propagation to parent clocks is undesirable,
41 * this function is recursively called to find the parent to calculate
42 * the accurate frequency.
43 */
developer65da8e72020-01-10 16:30:30 +080044static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
developerfd47f762022-09-09 20:00:01 +080045 struct udevice *pdev)
developer2186c982018-11-15 10:07:54 +080046{
47 struct clk parent = { .id = id, };
48
developerfd47f762022-09-09 20:00:01 +080049 if (pdev)
50 parent.dev = pdev;
51 else
developer2186c982018-11-15 10:07:54 +080052 parent.dev = clk->dev;
developer2186c982018-11-15 10:07:54 +080053
54 return clk_get_rate(&parent);
55}
56
57static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
Christian Marangia4143eb2024-06-28 19:40:50 +020058 u32 parent_type,
developer2186c982018-11-15 10:07:54 +080059 const struct mtk_composite *mux)
60{
61 u32 val, index = 0;
62
Christian Marangia4143eb2024-06-28 19:40:50 +020063 if (mux->flags & CLK_PARENT_MIXED) {
64 /*
65 * Assume parent_type in clk_tree to be always set with
66 * CLK_PARENT_MIXED implementation. If it's not, assume
67 * not parent clk ID clash is possible.
68 */
69 while (mux->parent_flags[index].id != parent ||
70 (parent_type && (mux->parent_flags[index].flags & CLK_PARENT_MASK) !=
71 parent_type))
72 if (++index == mux->num_parents)
73 return -EINVAL;
74 } else {
75 while (mux->parent[index] != parent)
76 if (++index == mux->num_parents)
77 return -EINVAL;
78 }
developer2186c982018-11-15 10:07:54 +080079
developerba560c72019-12-31 11:29:21 +080080 if (mux->flags & CLK_MUX_SETCLR_UPD) {
81 val = (mux->mux_mask << mux->mux_shift);
82 writel(val, base + mux->mux_clr_reg);
developer2186c982018-11-15 10:07:54 +080083
developerba560c72019-12-31 11:29:21 +080084 val = (index << mux->mux_shift);
85 writel(val, base + mux->mux_set_reg);
86
87 if (mux->upd_shift >= 0)
88 writel(BIT(mux->upd_shift), base + mux->upd_reg);
89 } else {
90 /* switch mux to a select parent */
91 val = readl(base + mux->mux_reg);
92 val &= ~(mux->mux_mask << mux->mux_shift);
93
94 val |= index << mux->mux_shift;
95 writel(val, base + mux->mux_reg);
96 }
developer2186c982018-11-15 10:07:54 +080097
98 return 0;
99}
100
101/* apmixedsys functions */
102
103static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll,
104 u32 fin, u32 pcw, int postdiv)
105{
106 int pcwbits = pll->pcwbits;
107 int pcwfbits;
developer0b5e5f12019-12-31 11:29:22 +0800108 int ibits;
developer2186c982018-11-15 10:07:54 +0800109 u64 vco;
110 u8 c = 0;
111
112 /* The fractional part of the PLL divider. */
developer0b5e5f12019-12-31 11:29:22 +0800113 ibits = pll->pcwibits ? pll->pcwibits : INTEGER_BITS;
114 pcwfbits = pcwbits > ibits ? pcwbits - ibits : 0;
developer2186c982018-11-15 10:07:54 +0800115
116 vco = (u64)fin * pcw;
117
118 if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
119 c = 1;
120
121 vco >>= pcwfbits;
122
123 if (c)
124 vco++;
125
126 return ((unsigned long)vco + postdiv - 1) / postdiv;
127}
128
129/**
130 * MediaTek PLLs are configured through their pcw value. The pcw value
131 * describes a divider in the PLL feedback loop which consists of 7 bits
132 * for the integer part and the remaining bits (if present) for the
133 * fractional part. Also they have a 3 bit power-of-two post divider.
134 */
135static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
136{
137 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
138 const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
developer0b5e5f12019-12-31 11:29:22 +0800139 u32 val, chg;
developer2186c982018-11-15 10:07:54 +0800140
141 /* set postdiv */
142 val = readl(priv->base + pll->pd_reg);
143 val &= ~(POSTDIV_MASK << pll->pd_shift);
144 val |= (ffs(postdiv) - 1) << pll->pd_shift;
145
146 /* postdiv and pcw need to set at the same time if on same register */
147 if (pll->pd_reg != pll->pcw_reg) {
148 writel(val, priv->base + pll->pd_reg);
149 val = readl(priv->base + pll->pcw_reg);
150 }
151
152 /* set pcw */
153 val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift);
154 val |= pcw << pll->pcw_shift;
developer2186c982018-11-15 10:07:54 +0800155
developer0b5e5f12019-12-31 11:29:22 +0800156 if (pll->pcw_chg_reg) {
157 chg = readl(priv->base + pll->pcw_chg_reg);
158 chg |= CON1_PCW_CHG;
159 writel(val, priv->base + pll->pcw_reg);
160 writel(chg, priv->base + pll->pcw_chg_reg);
161 } else {
162 val |= CON1_PCW_CHG;
163 writel(val, priv->base + pll->pcw_reg);
164 }
developer2186c982018-11-15 10:07:54 +0800165
166 udelay(20);
167}
168
169/**
170 * mtk_pll_calc_values - calculate good values for a given input frequency.
171 * @clk: The clk
172 * @pcw: The pcw value (output)
173 * @postdiv: The post divider (output)
174 * @freq: The desired target frequency
175 */
176static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
177 u32 freq)
178{
179 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
180 const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
developer0b5e5f12019-12-31 11:29:22 +0800181 unsigned long fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
developer2186c982018-11-15 10:07:54 +0800182 u64 _pcw;
developer0b5e5f12019-12-31 11:29:22 +0800183 int ibits;
developer2186c982018-11-15 10:07:54 +0800184 u32 val;
185
186 if (freq > pll->fmax)
187 freq = pll->fmax;
188
189 for (val = 0; val < 5; val++) {
190 *postdiv = 1 << val;
191 if ((u64)freq * *postdiv >= fmin)
192 break;
193 }
194
195 /* _pcw = freq * postdiv / xtal_rate * 2^pcwfbits */
developer0b5e5f12019-12-31 11:29:22 +0800196 ibits = pll->pcwibits ? pll->pcwibits : INTEGER_BITS;
197 _pcw = ((u64)freq << val) << (pll->pcwbits - ibits);
developer2186c982018-11-15 10:07:54 +0800198 do_div(_pcw, priv->tree->xtal2_rate);
199
200 *pcw = (u32)_pcw;
201}
202
203static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
204{
205 u32 pcw = 0;
206 u32 postdiv;
207
208 mtk_pll_calc_values(clk, &pcw, &postdiv, rate);
209 mtk_pll_set_rate_regs(clk, pcw, postdiv);
210
211 return 0;
212}
213
214static ulong mtk_apmixedsys_get_rate(struct clk *clk)
215{
216 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
217 const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
218 u32 postdiv;
219 u32 pcw;
220
221 postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) &
222 POSTDIV_MASK;
223 postdiv = 1 << postdiv;
224
225 pcw = readl(priv->base + pll->pcw_reg) >> pll->pcw_shift;
226 pcw &= GENMASK(pll->pcwbits - 1, 0);
227
228 return __mtk_pll_recalc_rate(pll, priv->tree->xtal2_rate,
229 pcw, postdiv);
230}
231
232static int mtk_apmixedsys_enable(struct clk *clk)
233{
234 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
235 const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
236 u32 r;
237
238 r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON;
239 writel(r, priv->base + pll->pwr_reg);
240 udelay(1);
241
242 r = readl(priv->base + pll->pwr_reg) & ~CON0_ISO_EN;
243 writel(r, priv->base + pll->pwr_reg);
244 udelay(1);
245
246 r = readl(priv->base + pll->reg + REG_CON0);
247 r |= pll->en_mask;
248 writel(r, priv->base + pll->reg + REG_CON0);
249
250 udelay(20);
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 return 0;
259}
260
261static int mtk_apmixedsys_disable(struct clk *clk)
262{
263 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
264 const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
265 u32 r;
266
267 if (pll->flags & HAVE_RST_BAR) {
268 r = readl(priv->base + pll->reg + REG_CON0);
269 r &= ~pll->rst_bar_mask;
270 writel(r, priv->base + pll->reg + REG_CON0);
271 }
272
273 r = readl(priv->base + pll->reg + REG_CON0);
274 r &= ~CON0_BASE_EN;
275 writel(r, priv->base + pll->reg + REG_CON0);
276
277 r = readl(priv->base + pll->pwr_reg) | CON0_ISO_EN;
278 writel(r, priv->base + pll->pwr_reg);
279
280 r = readl(priv->base + pll->pwr_reg) & ~CON0_PWR_ON;
281 writel(r, priv->base + pll->pwr_reg);
282
283 return 0;
284}
285
286/* topckgen functions */
287
288static ulong mtk_factor_recalc_rate(const struct mtk_fixed_factor *fdiv,
289 ulong parent_rate)
290{
291 u64 rate = parent_rate * fdiv->mult;
292
293 do_div(rate, fdiv->div);
294
295 return rate;
296}
297
developer65da8e72020-01-10 16:30:30 +0800298static ulong mtk_topckgen_get_factor_rate(struct clk *clk, u32 off)
developer2186c982018-11-15 10:07:54 +0800299{
300 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
301 const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off];
302 ulong rate;
303
304 switch (fdiv->flags & CLK_PARENT_MASK) {
305 case CLK_PARENT_APMIXED:
306 rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
developerfd47f762022-09-09 20:00:01 +0800307 priv->parent);
developer2186c982018-11-15 10:07:54 +0800308 break;
309 case CLK_PARENT_TOPCKGEN:
310 rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
311 break;
312
developerf724f112022-09-09 20:00:07 +0800313 case CLK_PARENT_XTAL:
developer2186c982018-11-15 10:07:54 +0800314 default:
315 rate = priv->tree->xtal_rate;
316 }
317
318 return mtk_factor_recalc_rate(fdiv, rate);
319}
320
developerad5b0752022-09-09 20:00:04 +0800321static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off)
322{
323 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
324 const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off];
325 ulong rate;
326
327 switch (fdiv->flags & CLK_PARENT_MASK) {
328 case CLK_PARENT_TOPCKGEN:
329 rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
330 priv->parent);
331 break;
developerf724f112022-09-09 20:00:07 +0800332 case CLK_PARENT_XTAL:
333 rate = priv->tree->xtal_rate;
334 break;
developerad5b0752022-09-09 20:00:04 +0800335 default:
336 rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
337 }
338
339 return mtk_factor_recalc_rate(fdiv, rate);
340}
341
developer65da8e72020-01-10 16:30:30 +0800342static ulong mtk_topckgen_get_mux_rate(struct clk *clk, u32 off)
developer2186c982018-11-15 10:07:54 +0800343{
344 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
345 const struct mtk_composite *mux = &priv->tree->muxes[off];
346 u32 index;
347
348 index = readl(priv->base + mux->mux_reg);
349 index &= mux->mux_mask << mux->mux_shift;
350 index = index >> mux->mux_shift;
351
developer2dc4caa2022-09-09 19:59:59 +0800352 if (mux->parent[index] > 0 ||
353 (mux->parent[index] == CLK_XTAL &&
developerfd47f762022-09-09 20:00:01 +0800354 priv->tree->flags & CLK_BYPASS_XTAL)) {
355 switch (mux->flags & CLK_PARENT_MASK) {
356 case CLK_PARENT_APMIXED:
357 return mtk_clk_find_parent_rate(clk, mux->parent[index],
358 priv->parent);
359 break;
360 default:
361 return mtk_clk_find_parent_rate(clk, mux->parent[index],
362 NULL);
363 break;
364 }
365 }
developer2186c982018-11-15 10:07:54 +0800366
367 return priv->tree->xtal_rate;
368}
369
Christian Marangia4143eb2024-06-28 19:40:50 +0200370static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
371 const int parent, u16 flags)
372{
373 switch (flags & CLK_PARENT_MASK) {
374 case CLK_PARENT_XTAL:
375 return priv->tree->xtal_rate;
376 case CLK_PARENT_TOPCKGEN:
377 return mtk_clk_find_parent_rate(clk, parent, priv->parent);
378 default:
379 return mtk_clk_find_parent_rate(clk, parent, NULL);
380 }
381}
382
developerad5b0752022-09-09 20:00:04 +0800383static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
384{
385 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
386 const struct mtk_composite *mux = &priv->tree->muxes[off];
387 u32 index;
388
389 index = readl(priv->base + mux->mux_reg);
390 index &= mux->mux_mask << mux->mux_shift;
391 index = index >> mux->mux_shift;
392
Christian Marangia4143eb2024-06-28 19:40:50 +0200393 /*
394 * Parents can be either from TOPCKGEN or INFRACFG,
395 * inspect the mtk_parent struct to check the source
396 */
397 if (mux->flags & CLK_PARENT_MIXED) {
398 const struct mtk_parent *parent = &mux->parent_flags[index];
399
400 return mtk_find_parent_rate(priv, clk, parent->id, parent->flags);
developerad5b0752022-09-09 20:00:04 +0800401 }
Christian Marangia4143eb2024-06-28 19:40:50 +0200402
403 if (mux->parent[index] == CLK_XTAL &&
404 !(priv->tree->flags & CLK_BYPASS_XTAL))
405 return priv->tree->xtal_rate;
406
407 return mtk_find_parent_rate(priv, clk, mux->parent[index], mux->flags);
developerad5b0752022-09-09 20:00:04 +0800408}
409
developer2186c982018-11-15 10:07:54 +0800410static ulong mtk_topckgen_get_rate(struct clk *clk)
411{
412 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
413
414 if (clk->id < priv->tree->fdivs_offs)
415 return priv->tree->fclks[clk->id].rate;
416 else if (clk->id < priv->tree->muxes_offs)
417 return mtk_topckgen_get_factor_rate(clk, clk->id -
418 priv->tree->fdivs_offs);
419 else
420 return mtk_topckgen_get_mux_rate(clk, clk->id -
421 priv->tree->muxes_offs);
developerad5b0752022-09-09 20:00:04 +0800422}
423
424static ulong mtk_infrasys_get_rate(struct clk *clk)
425{
426 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
427
428 ulong rate;
429
430 if (clk->id < priv->tree->fdivs_offs) {
431 rate = priv->tree->fclks[clk->id].rate;
432 } else if (clk->id < priv->tree->muxes_offs) {
433 rate = mtk_infrasys_get_factor_rate(clk, clk->id -
434 priv->tree->fdivs_offs);
Christian Marangibaa244c2024-06-28 19:40:48 +0200435 /* No gates defined or ID is a MUX */
436 } else if (!priv->tree->gates || clk->id < priv->tree->gates_offs) {
developerad5b0752022-09-09 20:00:04 +0800437 rate = mtk_infrasys_get_mux_rate(clk, clk->id -
438 priv->tree->muxes_offs);
Christian Marangibaa244c2024-06-28 19:40:48 +0200439 /* Only valid with muxes + gates implementation */
440 } else {
441 struct udevice *parent = NULL;
442 const struct mtk_gate *gate;
443
444 gate = &priv->tree->gates[clk->id - priv->tree->gates_offs];
445 if (gate->flags & CLK_PARENT_TOPCKGEN)
446 parent = priv->parent;
447 /*
448 * Assume xtal_rate to be declared if some gates have
449 * XTAL as parent
450 */
451 else if (gate->flags & CLK_PARENT_XTAL)
452 return priv->tree->xtal_rate;
453
454 rate = mtk_clk_find_parent_rate(clk, gate->parent, parent);
developerad5b0752022-09-09 20:00:04 +0800455 }
456
457 return rate;
developer2186c982018-11-15 10:07:54 +0800458}
459
developerfd47f762022-09-09 20:00:01 +0800460static int mtk_clk_mux_enable(struct clk *clk)
developer2186c982018-11-15 10:07:54 +0800461{
462 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
463 const struct mtk_composite *mux;
464 u32 val;
465
466 if (clk->id < priv->tree->muxes_offs)
467 return 0;
468
469 mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
470 if (mux->gate_shift < 0)
471 return 0;
472
473 /* enable clock gate */
developerba560c72019-12-31 11:29:21 +0800474 if (mux->flags & CLK_MUX_SETCLR_UPD) {
475 val = BIT(mux->gate_shift);
476 writel(val, priv->base + mux->mux_clr_reg);
477 } else {
478 val = readl(priv->base + mux->gate_reg);
479 val &= ~BIT(mux->gate_shift);
480 writel(val, priv->base + mux->gate_reg);
481 }
developer2186c982018-11-15 10:07:54 +0800482
483 if (mux->flags & CLK_DOMAIN_SCPSYS) {
484 /* enable scpsys clock off control */
485 writel(SCP_ARMCK_OFF_EN, priv->base + CLK_SCP_CFG0);
486 writel(SCP_AXICK_DCM_DIS_EN | SCP_AXICK_26M_SEL_EN,
487 priv->base + CLK_SCP_CFG1);
488 }
489
490 return 0;
491}
492
developerfd47f762022-09-09 20:00:01 +0800493static int mtk_clk_mux_disable(struct clk *clk)
developer2186c982018-11-15 10:07:54 +0800494{
495 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
496 const struct mtk_composite *mux;
497 u32 val;
498
499 if (clk->id < priv->tree->muxes_offs)
500 return 0;
501
502 mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
503 if (mux->gate_shift < 0)
504 return 0;
505
506 /* disable clock gate */
developerba560c72019-12-31 11:29:21 +0800507 if (mux->flags & CLK_MUX_SETCLR_UPD) {
508 val = BIT(mux->gate_shift);
509 writel(val, priv->base + mux->mux_set_reg);
510 } else {
511 val = readl(priv->base + mux->gate_reg);
512 val |= BIT(mux->gate_shift);
513 writel(val, priv->base + mux->gate_reg);
514 }
developer2186c982018-11-15 10:07:54 +0800515
516 return 0;
517}
518
developerfd47f762022-09-09 20:00:01 +0800519static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
developer2186c982018-11-15 10:07:54 +0800520{
Christian Marangia4143eb2024-06-28 19:40:50 +0200521 struct mtk_clk_priv *parent_priv = dev_get_priv(parent->dev);
developer2186c982018-11-15 10:07:54 +0800522 struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
Christian Marangia4143eb2024-06-28 19:40:50 +0200523 u32 parent_type;
developer2186c982018-11-15 10:07:54 +0800524
525 if (clk->id < priv->tree->muxes_offs)
526 return 0;
527
Christian Marangia4143eb2024-06-28 19:40:50 +0200528 if (!parent_priv)
529 return 0;
530
531 parent_type = parent_priv->tree->flags & CLK_PARENT_MASK;
532 return mtk_clk_mux_set_parent(priv->base, parent->id, parent_type,
developer2186c982018-11-15 10:07:54 +0800533 &priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
534}
535
536/* CG functions */
537
Christian Marangibaa244c2024-06-28 19:40:48 +0200538static int mtk_gate_enable(void __iomem *base, const struct mtk_gate *gate)
developer2186c982018-11-15 10:07:54 +0800539{
developer2186c982018-11-15 10:07:54 +0800540 u32 bit = BIT(gate->shift);
541
542 switch (gate->flags & CLK_GATE_MASK) {
543 case CLK_GATE_SETCLR:
Christian Marangibaa244c2024-06-28 19:40:48 +0200544 writel(bit, base + gate->regs->clr_ofs);
developer2186c982018-11-15 10:07:54 +0800545 break;
Fabien Parent69463e52019-03-24 16:46:35 +0100546 case CLK_GATE_SETCLR_INV:
Christian Marangibaa244c2024-06-28 19:40:48 +0200547 writel(bit, base + gate->regs->set_ofs);
Fabien Parent69463e52019-03-24 16:46:35 +0100548 break;
549 case CLK_GATE_NO_SETCLR:
Christian Marangibaa244c2024-06-28 19:40:48 +0200550 clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
Fabien Parent69463e52019-03-24 16:46:35 +0100551 break;
developer2186c982018-11-15 10:07:54 +0800552 case CLK_GATE_NO_SETCLR_INV:
Christian Marangibaa244c2024-06-28 19:40:48 +0200553 clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
developer2186c982018-11-15 10:07:54 +0800554 break;
555
556 default:
557 return -EINVAL;
558 }
559
560 return 0;
561}
562
Christian Marangibaa244c2024-06-28 19:40:48 +0200563static int mtk_clk_gate_enable(struct clk *clk)
developer2186c982018-11-15 10:07:54 +0800564{
565 struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200566 const struct mtk_gate *gate;
567
568 if (clk->id < priv->tree->gates_offs)
569 return -EINVAL;
Christian Marangibaa244c2024-06-28 19:40:48 +0200570
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200571 gate = &priv->gates[clk->id - priv->tree->gates_offs];
Christian Marangibaa244c2024-06-28 19:40:48 +0200572 return mtk_gate_enable(priv->base, gate);
573}
574
575static int mtk_clk_infrasys_enable(struct clk *clk)
576{
577 struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
578 const struct mtk_gate *gate;
579
580 /* MUX handling */
581 if (!priv->tree->gates || clk->id < priv->tree->gates_offs)
582 return mtk_clk_mux_enable(clk);
583
584 gate = &priv->tree->gates[clk->id - priv->tree->gates_offs];
585 return mtk_gate_enable(priv->base, gate);
586}
587
588static int mtk_gate_disable(void __iomem *base, const struct mtk_gate *gate)
589{
developer2186c982018-11-15 10:07:54 +0800590 u32 bit = BIT(gate->shift);
591
592 switch (gate->flags & CLK_GATE_MASK) {
593 case CLK_GATE_SETCLR:
Christian Marangibaa244c2024-06-28 19:40:48 +0200594 writel(bit, base + gate->regs->set_ofs);
developer2186c982018-11-15 10:07:54 +0800595 break;
Fabien Parent69463e52019-03-24 16:46:35 +0100596 case CLK_GATE_SETCLR_INV:
Christian Marangibaa244c2024-06-28 19:40:48 +0200597 writel(bit, base + gate->regs->clr_ofs);
Fabien Parent69463e52019-03-24 16:46:35 +0100598 break;
599 case CLK_GATE_NO_SETCLR:
Christian Marangibaa244c2024-06-28 19:40:48 +0200600 clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
Fabien Parent69463e52019-03-24 16:46:35 +0100601 break;
developer2186c982018-11-15 10:07:54 +0800602 case CLK_GATE_NO_SETCLR_INV:
Christian Marangibaa244c2024-06-28 19:40:48 +0200603 clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
developer2186c982018-11-15 10:07:54 +0800604 break;
605
606 default:
607 return -EINVAL;
608 }
609
610 return 0;
611}
612
Christian Marangibaa244c2024-06-28 19:40:48 +0200613static int mtk_clk_gate_disable(struct clk *clk)
614{
615 struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200616 const struct mtk_gate *gate;
Christian Marangibaa244c2024-06-28 19:40:48 +0200617
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200618 if (clk->id < priv->tree->gates_offs)
619 return -EINVAL;
620
621 gate = &priv->gates[clk->id - priv->tree->gates_offs];
Christian Marangibaa244c2024-06-28 19:40:48 +0200622 return mtk_gate_disable(priv->base, gate);
623}
624
625static int mtk_clk_infrasys_disable(struct clk *clk)
626{
627 struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
628 const struct mtk_gate *gate;
629
630 /* MUX handling */
631 if (!priv->tree->gates || clk->id < priv->tree->gates_offs)
632 return mtk_clk_mux_disable(clk);
633
634 gate = &priv->tree->gates[clk->id - priv->tree->gates_offs];
635 return mtk_gate_disable(priv->base, gate);
636}
637
developer2186c982018-11-15 10:07:54 +0800638static ulong mtk_clk_gate_get_rate(struct clk *clk)
639{
640 struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200641 const struct mtk_gate *gate;
642
643 if (clk->id < priv->tree->gates_offs)
644 return -EINVAL;
developer2186c982018-11-15 10:07:54 +0800645
Christian Marangi8f5b30c2024-06-28 19:40:49 +0200646 gate = &priv->gates[clk->id - priv->tree->gates_offs];
Christian Marangi16f5f3f2024-06-28 19:40:46 +0200647 /*
648 * Assume xtal_rate to be declared if some gates have
649 * XTAL as parent
650 */
651 if (gate->flags & CLK_PARENT_XTAL)
652 return priv->tree->xtal_rate;
653
developerfd47f762022-09-09 20:00:01 +0800654 return mtk_clk_find_parent_rate(clk, gate->parent, priv->parent);
developer2186c982018-11-15 10:07:54 +0800655}
656
657const struct clk_ops mtk_clk_apmixedsys_ops = {
658 .enable = mtk_apmixedsys_enable,
659 .disable = mtk_apmixedsys_disable,
660 .set_rate = mtk_apmixedsys_set_rate,
661 .get_rate = mtk_apmixedsys_get_rate,
662};
663
664const struct clk_ops mtk_clk_topckgen_ops = {
developerfd47f762022-09-09 20:00:01 +0800665 .enable = mtk_clk_mux_enable,
666 .disable = mtk_clk_mux_disable,
developer2186c982018-11-15 10:07:54 +0800667 .get_rate = mtk_topckgen_get_rate,
developerfd47f762022-09-09 20:00:01 +0800668 .set_parent = mtk_common_clk_set_parent,
developer2186c982018-11-15 10:07:54 +0800669};
670
developerad5b0752022-09-09 20:00:04 +0800671const struct clk_ops mtk_clk_infrasys_ops = {
Christian Marangibaa244c2024-06-28 19:40:48 +0200672 .enable = mtk_clk_infrasys_enable,
673 .disable = mtk_clk_infrasys_disable,
developerad5b0752022-09-09 20:00:04 +0800674 .get_rate = mtk_infrasys_get_rate,
675 .set_parent = mtk_common_clk_set_parent,
676};
677
developer2186c982018-11-15 10:07:54 +0800678const struct clk_ops mtk_clk_gate_ops = {
679 .enable = mtk_clk_gate_enable,
680 .disable = mtk_clk_gate_disable,
681 .get_rate = mtk_clk_gate_get_rate,
682};
683
684int mtk_common_clk_init(struct udevice *dev,
685 const struct mtk_clk_tree *tree)
686{
687 struct mtk_clk_priv *priv = dev_get_priv(dev);
developerfd47f762022-09-09 20:00:01 +0800688 struct udevice *parent;
689 int ret;
developer2186c982018-11-15 10:07:54 +0800690
691 priv->base = dev_read_addr_ptr(dev);
692 if (!priv->base)
693 return -ENOENT;
694
developerfd47f762022-09-09 20:00:01 +0800695 ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
696 if (ret || !parent) {
697 ret = uclass_get_device_by_driver(UCLASS_CLK,
698 DM_DRIVER_GET(mtk_clk_apmixedsys), &parent);
699 if (ret || !parent)
700 return -ENOENT;
701 }
702
703 priv->parent = parent;
developer2186c982018-11-15 10:07:54 +0800704 priv->tree = tree;
705
706 return 0;
707}
708
709int mtk_common_clk_gate_init(struct udevice *dev,
710 const struct mtk_clk_tree *tree,
711 const struct mtk_gate *gates)
712{
713 struct mtk_cg_priv *priv = dev_get_priv(dev);
developerfd47f762022-09-09 20:00:01 +0800714 struct udevice *parent;
715 int ret;
developer2186c982018-11-15 10:07:54 +0800716
717 priv->base = dev_read_addr_ptr(dev);
718 if (!priv->base)
719 return -ENOENT;
720
developerfd47f762022-09-09 20:00:01 +0800721 ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
722 if (ret || !parent) {
723 ret = uclass_get_device_by_driver(UCLASS_CLK,
724 DM_DRIVER_GET(mtk_clk_topckgen), &parent);
725 if (ret || !parent)
726 return -ENOENT;
727 }
728
729 priv->parent = parent;
developer2186c982018-11-15 10:07:54 +0800730 priv->tree = tree;
731 priv->gates = gates;
732
733 return 0;
734}