blob: c1976aa1efb15644f7611fa709c462e4b8c4b0ca [file] [log] [blame]
Jerome Brunetd03f5f02019-02-11 16:45:01 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
4 * (C) Copyright 2018 - BayLibre, SAS
5 * Author: Neil Armstrong <narmstrong@baylibre.com>
6 */
7
8#include <common.h>
9#include <asm/arch/clock-g12a.h>
10#include <asm/io.h>
11#include <clk-uclass.h>
12#include <dm.h>
13#include <regmap.h>
14#include <syscon.h>
15#include <div64.h>
16#include <dt-bindings/clock/g12a-clkc.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Neil Armstrong4371b9c2019-08-30 14:09:22 +020018#include <linux/kernel.h>
Jerome Brunetd03f5f02019-02-11 16:45:01 +010019#include "clk_meson.h"
20
Neil Armstrong4371b9c2019-08-30 14:09:22 +020021/* This driver support only basic clock tree operations :
22 * - Can calculate clock frequency on a limited tree
23 * - Can Read muxes and basic dividers (0-based only)
24 * - Can enable/disable gates with limited propagation
25 * - Can reparent without propagation, only on muxes
26 * - Can set rates without reparenting
27 * This driver is adapted to what is actually supported by U-Boot
28 */
29
30/* Only the clocks ids we don't want to expose, such as the internal muxes
31 * and dividers of composite clocks, will remain defined here.
32 */
33#define CLKID_MPEG_SEL 8
34#define CLKID_MPEG_DIV 9
35#define CLKID_SD_EMMC_A_CLK0_SEL 63
36#define CLKID_SD_EMMC_A_CLK0_DIV 64
37#define CLKID_SD_EMMC_B_CLK0_SEL 65
38#define CLKID_SD_EMMC_B_CLK0_DIV 66
39#define CLKID_SD_EMMC_C_CLK0_SEL 67
40#define CLKID_SD_EMMC_C_CLK0_DIV 68
41#define CLKID_MPLL0_DIV 69
42#define CLKID_MPLL1_DIV 70
43#define CLKID_MPLL2_DIV 71
44#define CLKID_MPLL3_DIV 72
45#define CLKID_MPLL_PREDIV 73
46#define CLKID_FCLK_DIV2_DIV 75
47#define CLKID_FCLK_DIV3_DIV 76
48#define CLKID_FCLK_DIV4_DIV 77
49#define CLKID_FCLK_DIV5_DIV 78
50#define CLKID_FCLK_DIV7_DIV 79
51#define CLKID_FCLK_DIV2P5_DIV 100
52#define CLKID_FIXED_PLL_DCO 101
53#define CLKID_SYS_PLL_DCO 102
54#define CLKID_GP0_PLL_DCO 103
55#define CLKID_HIFI_PLL_DCO 104
56#define CLKID_VPU_0_DIV 111
57#define CLKID_VPU_1_DIV 114
58#define CLKID_VAPB_0_DIV 118
59#define CLKID_VAPB_1_DIV 121
60#define CLKID_HDMI_PLL_DCO 125
61#define CLKID_HDMI_PLL_OD 126
62#define CLKID_HDMI_PLL_OD2 127
63#define CLKID_VID_PLL_SEL 130
64#define CLKID_VID_PLL_DIV 131
65#define CLKID_VCLK_SEL 132
66#define CLKID_VCLK2_SEL 133
67#define CLKID_VCLK_INPUT 134
68#define CLKID_VCLK2_INPUT 135
69#define CLKID_VCLK_DIV 136
70#define CLKID_VCLK2_DIV 137
71#define CLKID_VCLK_DIV2_EN 140
72#define CLKID_VCLK_DIV4_EN 141
73#define CLKID_VCLK_DIV6_EN 142
74#define CLKID_VCLK_DIV12_EN 143
75#define CLKID_VCLK2_DIV2_EN 144
76#define CLKID_VCLK2_DIV4_EN 145
77#define CLKID_VCLK2_DIV6_EN 146
78#define CLKID_VCLK2_DIV12_EN 147
79#define CLKID_CTS_ENCI_SEL 158
80#define CLKID_CTS_ENCP_SEL 159
81#define CLKID_CTS_VDAC_SEL 160
82#define CLKID_HDMI_TX_SEL 161
83#define CLKID_HDMI_SEL 166
84#define CLKID_HDMI_DIV 167
85#define CLKID_MALI_0_DIV 170
86#define CLKID_MALI_1_DIV 173
87
88#define CLKID_XTAL 0x10000000
89
Jerome Brunetd03f5f02019-02-11 16:45:01 +010090#define XTAL_RATE 24000000
91
92struct meson_clk {
93 struct regmap *map;
94};
95
Neil Armstrong4371b9c2019-08-30 14:09:22 +020096static ulong meson_div_get_rate(struct clk *clk, unsigned long id);
97static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate,
98 ulong current_rate);
99static ulong meson_mux_set_parent(struct clk *clk, unsigned long id,
100 unsigned long parent_id);
101static ulong meson_mux_get_rate(struct clk *clk, unsigned long id);
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200102static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
103 ulong rate, ulong current_rate);
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200104static ulong meson_mux_get_parent(struct clk *clk, unsigned long id);
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100105static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
106
107#define NUM_CLKS 178
108
109static struct meson_gate gates[NUM_CLKS] = {
110 /* Everything Else (EE) domain gates */
111 MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8),
112 MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9),
113 MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13),
114 MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 14),
115 MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25),
116 MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26),
117 MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3),
118 MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16),
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200119 MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 25),
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200120 MESON_GATE(CLKID_HTX_PCLK, HHI_GCLK_MPEG2, 4),
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200121 MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8),
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200122 MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25),
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100123
124 /* Peripheral Gates */
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200125 MESON_GATE(CLKID_FCLK_DIV2, HHI_FIX_PLL_CNTL1, 24),
126 MESON_GATE(CLKID_FCLK_DIV3, HHI_FIX_PLL_CNTL1, 20),
127 MESON_GATE(CLKID_FCLK_DIV4, HHI_FIX_PLL_CNTL1, 21),
128 MESON_GATE(CLKID_FCLK_DIV5, HHI_FIX_PLL_CNTL1, 22),
129 MESON_GATE(CLKID_FCLK_DIV7, HHI_FIX_PLL_CNTL1, 23),
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100130 MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23),
131 MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7),
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200132 MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8),
133 MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24),
134 MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8),
135 MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24),
136 MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30),
137 MESON_GATE(CLKID_HDMI, HHI_HDMI_CLK_CNTL, 8),
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100138};
139
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200140static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on)
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100141{
142 struct meson_clk *priv = dev_get_priv(clk->dev);
143 struct meson_gate *gate;
144
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200145 debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id);
146
147 /* Propagate through muxes */
148 switch (id) {
149 case CLKID_VPU:
150 return meson_set_gate_by_id(clk,
151 meson_mux_get_parent(clk, CLKID_VPU), on);
152 case CLKID_VAPB_SEL:
153 return meson_set_gate_by_id(clk,
154 meson_mux_get_parent(clk, CLKID_VAPB_SEL), on);
155 }
156
157 if (id >= ARRAY_SIZE(gates))
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100158 return -ENOENT;
159
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200160 gate = &gates[id];
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100161
162 if (gate->reg == 0)
163 return 0;
164
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200165 debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id);
166
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100167 regmap_update_bits(priv->map, gate->reg,
168 BIT(gate->bit), on ? BIT(gate->bit) : 0);
169
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200170 /* Propagate to next gate(s) */
171 switch (id) {
172 case CLKID_VAPB:
173 return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on);
174 case CLKID_VAPB_0:
175 return meson_set_gate_by_id(clk,
176 meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on);
177 case CLKID_VAPB_1:
178 return meson_set_gate_by_id(clk,
179 meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on);
180 case CLKID_VPU_0:
181 return meson_set_gate_by_id(clk,
182 meson_mux_get_parent(clk, CLKID_VPU_0_SEL), on);
183 case CLKID_VPU_1:
184 return meson_set_gate_by_id(clk,
185 meson_mux_get_parent(clk, CLKID_VPU_1_SEL), on);
186 }
187
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100188 return 0;
189}
190
191static int meson_clk_enable(struct clk *clk)
192{
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200193 return meson_set_gate_by_id(clk, clk->id, true);
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100194}
195
196static int meson_clk_disable(struct clk *clk)
197{
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200198 return meson_set_gate_by_id(clk, clk->id, false);
199}
200
201static struct parm meson_vpu_0_div_parm = {
202 HHI_VPU_CLK_CNTL, 0, 7,
203};
204
205int meson_vpu_0_div_parent = CLKID_VPU_0_SEL;
206
207static struct parm meson_vpu_1_div_parm = {
208 HHI_VPU_CLK_CNTL, 16, 7,
209};
210
211int meson_vpu_1_div_parent = CLKID_VPU_1_SEL;
212
213static struct parm meson_vapb_0_div_parm = {
214 HHI_VAPBCLK_CNTL, 0, 7,
215};
216
217int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL;
218
219static struct parm meson_vapb_1_div_parm = {
220 HHI_VAPBCLK_CNTL, 16, 7,
221};
222
223int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL;
224
225static struct parm meson_hdmi_div_parm = {
226 HHI_HDMI_CLK_CNTL, 0, 7,
227};
228
229int meson_hdmi_div_parent = CLKID_HDMI_SEL;
230
231static ulong meson_div_get_rate(struct clk *clk, unsigned long id)
232{
233 struct meson_clk *priv = dev_get_priv(clk->dev);
234 unsigned int rate, parent_rate;
235 struct parm *parm;
236 int parent;
237 uint reg;
238
239 switch (id) {
240 case CLKID_VPU_0_DIV:
241 parm = &meson_vpu_0_div_parm;
242 parent = meson_vpu_0_div_parent;
243 break;
244 case CLKID_VPU_1_DIV:
245 parm = &meson_vpu_1_div_parm;
246 parent = meson_vpu_1_div_parent;
247 break;
248 case CLKID_VAPB_0_DIV:
249 parm = &meson_vapb_0_div_parm;
250 parent = meson_vapb_0_div_parent;
251 break;
252 case CLKID_VAPB_1_DIV:
253 parm = &meson_vapb_1_div_parm;
254 parent = meson_vapb_1_div_parent;
255 break;
256 case CLKID_HDMI_DIV:
257 parm = &meson_hdmi_div_parm;
258 parent = meson_hdmi_div_parent;
259 break;
260 default:
261 return -ENOENT;
262 }
263
264 regmap_read(priv->map, parm->reg_off, &reg);
265 reg = PARM_GET(parm->width, parm->shift, reg);
266
267 debug("%s: div of %ld is %d\n", __func__, id, reg + 1);
268
269 parent_rate = meson_clk_get_rate_by_id(clk, parent);
270 if (IS_ERR_VALUE(parent_rate))
271 return parent_rate;
272
273 debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate);
274
275 rate = parent_rate / (reg + 1);
276
277 debug("%s: rate of %ld is %d\n", __func__, id, rate);
278
279 return rate;
280}
281
282static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate,
283 ulong current_rate)
284{
285 struct meson_clk *priv = dev_get_priv(clk->dev);
286 unsigned int new_div = -EINVAL;
287 unsigned long parent_rate;
288 struct parm *parm;
289 int parent;
290 int ret;
291
292 if (current_rate == rate)
293 return 0;
294
295 debug("%s: setting rate of %ld from %ld to %ld\n",
296 __func__, id, current_rate, rate);
297
298 switch (id) {
299 case CLKID_VPU_0_DIV:
300 parm = &meson_vpu_0_div_parm;
301 parent = meson_vpu_0_div_parent;
302 break;
303 case CLKID_VPU_1_DIV:
304 parm = &meson_vpu_1_div_parm;
305 parent = meson_vpu_1_div_parent;
306 break;
307 case CLKID_VAPB_0_DIV:
308 parm = &meson_vapb_0_div_parm;
309 parent = meson_vapb_0_div_parent;
310 break;
311 case CLKID_VAPB_1_DIV:
312 parm = &meson_vapb_1_div_parm;
313 parent = meson_vapb_1_div_parent;
314 break;
315 case CLKID_HDMI_DIV:
316 parm = &meson_hdmi_div_parm;
317 parent = meson_hdmi_div_parent;
318 break;
319 default:
320 return -ENOENT;
321 }
322
323 parent_rate = meson_clk_get_rate_by_id(clk, parent);
324 if (IS_ERR_VALUE(parent_rate))
325 return parent_rate;
326
327 debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate);
328
329 /* If can't divide, set parent instead */
330 if (!parent_rate || rate > parent_rate)
331 return meson_clk_set_rate_by_id(clk, parent, rate,
332 current_rate);
333
334 new_div = DIV_ROUND_CLOSEST(parent_rate, rate);
335
336 debug("%s: new div of %ld is %d\n", __func__, id, new_div);
337
338 /* If overflow, try to set parent rate and retry */
339 if (!new_div || new_div > (1 << parm->width)) {
340 ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate);
341 if (IS_ERR_VALUE(ret))
342 return ret;
343
344 parent_rate = meson_clk_get_rate_by_id(clk, parent);
345 if (IS_ERR_VALUE(parent_rate))
346 return parent_rate;
347
348 new_div = DIV_ROUND_CLOSEST(parent_rate, rate);
349
350 debug("%s: new new div of %ld is %d\n", __func__, id, new_div);
351
352 if (!new_div || new_div > (1 << parm->width))
353 return -EINVAL;
354 }
355
356 debug("%s: setting div of %ld to %d\n", __func__, id, new_div);
357
358 regmap_update_bits(priv->map, parm->reg_off,
359 SETPMASK(parm->width, parm->shift),
360 (new_div - 1) << parm->shift);
361
362 debug("%s: new rate of %ld is %ld\n",
363 __func__, id, meson_div_get_rate(clk, id));
364
365 return 0;
366}
367
368static struct parm meson_vpu_mux_parm = {
369 HHI_VPU_CLK_CNTL, 31, 1,
370};
371
372int meson_vpu_mux_parents[] = {
373 CLKID_VPU_0,
374 CLKID_VPU_1,
375};
376
377static struct parm meson_vpu_0_mux_parm = {
378 HHI_VPU_CLK_CNTL, 9, 3,
379};
380
381static struct parm meson_vpu_1_mux_parm = {
382 HHI_VPU_CLK_CNTL, 25, 3,
383};
384
385static int meson_vpu_0_1_mux_parents[] = {
386 CLKID_FCLK_DIV3,
387 CLKID_FCLK_DIV4,
388 CLKID_FCLK_DIV5,
389 CLKID_FCLK_DIV7,
390 -ENOENT,
391 -ENOENT,
392 -ENOENT,
393 -ENOENT,
394};
395
396static struct parm meson_vapb_sel_mux_parm = {
397 HHI_VAPBCLK_CNTL, 31, 1,
398};
399
400int meson_vapb_sel_mux_parents[] = {
401 CLKID_VAPB_0,
402 CLKID_VAPB_1,
403};
404
405static struct parm meson_vapb_0_mux_parm = {
406 HHI_VAPBCLK_CNTL, 9, 2,
407};
408
409static struct parm meson_vapb_1_mux_parm = {
410 HHI_VAPBCLK_CNTL, 25, 2,
411};
412
413static int meson_vapb_0_1_mux_parents[] = {
414 CLKID_FCLK_DIV4,
415 CLKID_FCLK_DIV3,
416 CLKID_FCLK_DIV5,
417 CLKID_FCLK_DIV7,
418};
419
420static struct parm meson_hdmi_mux_parm = {
421 HHI_HDMI_CLK_CNTL, 9, 2,
422};
423
424static int meson_hdmi_mux_parents[] = {
425 CLKID_XTAL,
426 CLKID_FCLK_DIV4,
427 CLKID_FCLK_DIV3,
428 CLKID_FCLK_DIV5,
429};
430
431static ulong meson_mux_get_parent(struct clk *clk, unsigned long id)
432{
433 struct meson_clk *priv = dev_get_priv(clk->dev);
434 struct parm *parm;
435 int *parents;
436 uint reg;
437
438 switch (id) {
439 case CLKID_VPU:
440 parm = &meson_vpu_mux_parm;
441 parents = meson_vpu_mux_parents;
442 break;
443 case CLKID_VPU_0_SEL:
444 parm = &meson_vpu_0_mux_parm;
445 parents = meson_vpu_0_1_mux_parents;
446 break;
447 case CLKID_VPU_1_SEL:
448 parm = &meson_vpu_1_mux_parm;
449 parents = meson_vpu_0_1_mux_parents;
450 break;
451 case CLKID_VAPB_SEL:
452 parm = &meson_vapb_sel_mux_parm;
453 parents = meson_vapb_sel_mux_parents;
454 break;
455 case CLKID_VAPB_0_SEL:
456 parm = &meson_vapb_0_mux_parm;
457 parents = meson_vapb_0_1_mux_parents;
458 break;
459 case CLKID_VAPB_1_SEL:
460 parm = &meson_vapb_1_mux_parm;
461 parents = meson_vapb_0_1_mux_parents;
462 break;
463 case CLKID_HDMI_SEL:
464 parm = &meson_hdmi_mux_parm;
465 parents = meson_hdmi_mux_parents;
466 break;
467 default:
468 return -ENOENT;
469 }
470
471 regmap_read(priv->map, parm->reg_off, &reg);
472 reg = PARM_GET(parm->width, parm->shift, reg);
473
474 debug("%s: parent of %ld is %d (%d)\n",
475 __func__, id, parents[reg], reg);
476
477 return parents[reg];
478}
479
480static ulong meson_mux_set_parent(struct clk *clk, unsigned long id,
481 unsigned long parent_id)
482{
483 unsigned long cur_parent = meson_mux_get_parent(clk, id);
484 struct meson_clk *priv = dev_get_priv(clk->dev);
485 unsigned int new_index = -EINVAL;
486 struct parm *parm;
487 int *parents;
488 int i;
489
490 if (IS_ERR_VALUE(cur_parent))
491 return cur_parent;
492
493 debug("%s: setting parent of %ld from %ld to %ld\n",
494 __func__, id, cur_parent, parent_id);
495
496 if (cur_parent == parent_id)
497 return 0;
498
499 switch (id) {
500 case CLKID_VPU:
501 parm = &meson_vpu_mux_parm;
502 parents = meson_vpu_mux_parents;
503 break;
504 case CLKID_VPU_0_SEL:
505 parm = &meson_vpu_0_mux_parm;
506 parents = meson_vpu_0_1_mux_parents;
507 break;
508 case CLKID_VPU_1_SEL:
509 parm = &meson_vpu_1_mux_parm;
510 parents = meson_vpu_0_1_mux_parents;
511 break;
512 case CLKID_VAPB_SEL:
513 parm = &meson_vapb_sel_mux_parm;
514 parents = meson_vapb_sel_mux_parents;
515 break;
516 case CLKID_VAPB_0_SEL:
517 parm = &meson_vapb_0_mux_parm;
518 parents = meson_vapb_0_1_mux_parents;
519 break;
520 case CLKID_VAPB_1_SEL:
521 parm = &meson_vapb_1_mux_parm;
522 parents = meson_vapb_0_1_mux_parents;
523 break;
524 case CLKID_HDMI_SEL:
525 parm = &meson_hdmi_mux_parm;
526 parents = meson_hdmi_mux_parents;
527 break;
528 default:
529 /* Not a mux */
530 return -ENOENT;
531 }
532
533 for (i = 0 ; i < (1 << parm->width) ; ++i) {
534 if (parents[i] == parent_id)
535 new_index = i;
536 }
537
538 if (IS_ERR_VALUE(new_index))
539 return new_index;
540
541 debug("%s: new index of %ld is %d\n", __func__, id, new_index);
542
543 regmap_update_bits(priv->map, parm->reg_off,
544 SETPMASK(parm->width, parm->shift),
545 new_index << parm->shift);
546
547 debug("%s: new parent of %ld is %ld\n",
548 __func__, id, meson_mux_get_parent(clk, id));
549
550 return 0;
551}
552
553static ulong meson_mux_get_rate(struct clk *clk, unsigned long id)
554{
555 int parent = meson_mux_get_parent(clk, id);
556
557 if (IS_ERR_VALUE(parent))
558 return parent;
559
560 return meson_clk_get_rate_by_id(clk, parent);
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100561}
562
563static unsigned long meson_clk81_get_rate(struct clk *clk)
564{
565 struct meson_clk *priv = dev_get_priv(clk->dev);
566 unsigned long parent_rate;
567 uint reg;
568 int parents[] = {
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200569 CLKID_XTAL,
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100570 -1,
571 CLKID_FCLK_DIV7,
572 CLKID_MPLL1,
573 CLKID_MPLL2,
574 CLKID_FCLK_DIV4,
575 CLKID_FCLK_DIV3,
576 CLKID_FCLK_DIV5
577 };
578
579 /* mux */
580 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
581 reg = (reg >> 12) & 7;
582
583 switch (reg) {
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100584 case 1:
585 return -ENOENT;
586 default:
587 parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]);
588 }
589
590 /* divider */
591 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
592 reg = reg & ((1 << 7) - 1);
593
594 return parent_rate / reg;
595}
596
597static long mpll_rate_from_params(unsigned long parent_rate,
598 unsigned long sdm,
599 unsigned long n2)
600{
601 unsigned long divisor = (SDM_DEN * n2) + sdm;
602
603 if (n2 < N2_MIN)
604 return -EINVAL;
605
606 return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
607}
608
609static struct parm meson_mpll0_parm[2] = {
610 {HHI_MPLL_CNTL1, 0, 14}, /* psdm */
611 {HHI_MPLL_CNTL1, 20, 9}, /* pn2 */
612};
613
614static struct parm meson_mpll1_parm[2] = {
615 {HHI_MPLL_CNTL3, 0, 14}, /* psdm */
616 {HHI_MPLL_CNTL3, 20, 9}, /* pn2 */
617};
618
619static struct parm meson_mpll2_parm[2] = {
620 {HHI_MPLL_CNTL5, 0, 14}, /* psdm */
621 {HHI_MPLL_CNTL5, 20, 9}, /* pn2 */
622};
623
624/*
625 * MultiPhase Locked Loops are outputs from a PLL with additional frequency
626 * scaling capabilities. MPLL rates are calculated as:
627 *
628 * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
629 */
630static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id)
631{
632 struct meson_clk *priv = dev_get_priv(clk->dev);
633 struct parm *psdm, *pn2;
634 unsigned long sdm, n2;
635 unsigned long parent_rate;
636 uint reg;
637
638 switch (id) {
639 case CLKID_MPLL0:
640 psdm = &meson_mpll0_parm[0];
641 pn2 = &meson_mpll0_parm[1];
642 break;
643 case CLKID_MPLL1:
644 psdm = &meson_mpll1_parm[0];
645 pn2 = &meson_mpll1_parm[1];
646 break;
647 case CLKID_MPLL2:
648 psdm = &meson_mpll2_parm[0];
649 pn2 = &meson_mpll2_parm[1];
650 break;
651 default:
652 return -ENOENT;
653 }
654
655 parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL);
656 if (IS_ERR_VALUE(parent_rate))
657 return parent_rate;
658
659 regmap_read(priv->map, psdm->reg_off, &reg);
660 sdm = PARM_GET(psdm->width, psdm->shift, reg);
661
662 regmap_read(priv->map, pn2->reg_off, &reg);
663 n2 = PARM_GET(pn2->width, pn2->shift, reg);
664
665 return mpll_rate_from_params(parent_rate, sdm, n2);
666}
667
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200668static struct parm meson_fixed_pll_parm[4] = {
669 {HHI_FIX_PLL_CNTL0, 0, 9}, /* pm */
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100670 {HHI_FIX_PLL_CNTL0, 10, 5}, /* pn */
671 {HHI_FIX_PLL_CNTL0, 16, 2}, /* pod */
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200672 {HHI_FIX_PLL_CNTL1, 0, 17}, /* pfrac */
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100673};
674
675static struct parm meson_sys_pll_parm[3] = {
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200676 {HHI_SYS_PLL_CNTL0, 0, 9}, /* pm */
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100677 {HHI_SYS_PLL_CNTL0, 10, 5}, /* pn */
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200678 {HHI_SYS_PLL_CNTL0, 16, 3}, /* pod */
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100679};
680
681static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
682{
683 struct meson_clk *priv = dev_get_priv(clk->dev);
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200684 struct parm *pm, *pn, *pod, *pfrac = NULL;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100685 unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200686 u16 n, m, od, frac;
687 ulong rate;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100688 uint reg;
689
690 /*
691 * FIXME: Between the unit conversion and the missing frac, we know
692 * rate will be slightly off ...
693 */
694
695 switch (id) {
696 case CLKID_FIXED_PLL:
697 pm = &meson_fixed_pll_parm[0];
698 pn = &meson_fixed_pll_parm[1];
699 pod = &meson_fixed_pll_parm[2];
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200700 pfrac = &meson_fixed_pll_parm[3];
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100701 break;
702 case CLKID_SYS_PLL:
703 pm = &meson_sys_pll_parm[0];
704 pn = &meson_sys_pll_parm[1];
705 pod = &meson_sys_pll_parm[2];
706 break;
707 default:
708 return -ENOENT;
709 }
710
711 regmap_read(priv->map, pn->reg_off, &reg);
712 n = PARM_GET(pn->width, pn->shift, reg);
713
714 regmap_read(priv->map, pm->reg_off, &reg);
715 m = PARM_GET(pm->width, pm->shift, reg);
716
717 regmap_read(priv->map, pod->reg_off, &reg);
718 od = PARM_GET(pod->width, pod->shift, reg);
719
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200720 rate = parent_rate_mhz * m;
721
722 if (pfrac) {
723 ulong frac_rate;
724
725 regmap_read(priv->map, pfrac->reg_off, &reg);
726 frac = PARM_GET(pfrac->width - 1, pfrac->shift, reg);
727
728 frac_rate = DIV_ROUND_UP_ULL((u64)parent_rate_mhz * frac,
729 1 << (pfrac->width - 2));
730
731 if (frac & BIT(pfrac->width - 1))
732 rate -= frac_rate;
733 else
734 rate += frac_rate;
735 }
736
737 return (DIV_ROUND_UP_ULL(rate, n) >> od) * 1000000;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100738}
739
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200740static struct parm meson_pcie_pll_parm[3] = {
741 {HHI_PCIE_PLL_CNTL0, 0, 8}, /* pm */
742 {HHI_PCIE_PLL_CNTL0, 10, 5}, /* pn */
743 {HHI_PCIE_PLL_CNTL0, 16, 5}, /* pod */
744};
745
746static ulong meson_pcie_pll_get_rate(struct clk *clk)
747{
748 struct meson_clk *priv = dev_get_priv(clk->dev);
749 struct parm *pm, *pn, *pod;
750 unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
751 u16 n, m, od;
752 uint reg;
753
754 pm = &meson_pcie_pll_parm[0];
755 pn = &meson_pcie_pll_parm[1];
756 pod = &meson_pcie_pll_parm[2];
757
758 regmap_read(priv->map, pn->reg_off, &reg);
759 n = PARM_GET(pn->width, pn->shift, reg);
760
761 regmap_read(priv->map, pm->reg_off, &reg);
762 m = PARM_GET(pm->width, pm->shift, reg);
763
764 regmap_read(priv->map, pod->reg_off, &reg);
765 od = PARM_GET(pod->width, pod->shift, reg);
766
767 return ((parent_rate_mhz * m / n) / 2 / od / 2) * 1000000;
768}
769
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100770static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
771{
772 ulong rate;
773
774 switch (id) {
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200775 case CLKID_XTAL:
776 rate = XTAL_RATE;
777 break;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100778 case CLKID_FIXED_PLL:
779 case CLKID_SYS_PLL:
780 rate = meson_pll_get_rate(clk, id);
781 break;
782 case CLKID_FCLK_DIV2:
783 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2;
784 break;
785 case CLKID_FCLK_DIV3:
786 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3;
787 break;
788 case CLKID_FCLK_DIV4:
789 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4;
790 break;
791 case CLKID_FCLK_DIV5:
792 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5;
793 break;
794 case CLKID_FCLK_DIV7:
795 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7;
796 break;
797 case CLKID_MPLL0:
798 case CLKID_MPLL1:
799 case CLKID_MPLL2:
800 rate = meson_mpll_get_rate(clk, id);
801 break;
802 case CLKID_CLK81:
803 rate = meson_clk81_get_rate(clk);
804 break;
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200805 case CLKID_PCIE_PLL:
806 rate = meson_pcie_pll_get_rate(clk);
Heinrich Schuchardt6572c452020-02-15 21:10:54 +0100807 break;
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200808 case CLKID_VPU_0:
809 rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV);
810 break;
811 case CLKID_VPU_1:
812 rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV);
813 break;
814 case CLKID_VAPB:
815 rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL);
816 break;
817 case CLKID_VAPB_0:
818 rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV);
819 break;
820 case CLKID_VAPB_1:
821 rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV);
822 break;
823 case CLKID_HDMI:
824 rate = meson_div_get_rate(clk, CLKID_HDMI_DIV);
825 break;
826 case CLKID_VPU_0_DIV:
827 case CLKID_VPU_1_DIV:
828 case CLKID_VAPB_0_DIV:
829 case CLKID_VAPB_1_DIV:
830 case CLKID_HDMI_DIV:
831 rate = meson_div_get_rate(clk, id);
832 break;
833 case CLKID_VPU:
834 case CLKID_VPU_0_SEL:
835 case CLKID_VPU_1_SEL:
836 case CLKID_VAPB_SEL:
837 case CLKID_VAPB_0_SEL:
838 case CLKID_VAPB_1_SEL:
839 case CLKID_HDMI_SEL:
840 rate = meson_mux_get_rate(clk, id);
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200841 break;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100842 default:
843 if (gates[id].reg != 0) {
844 /* a clock gate */
845 rate = meson_clk81_get_rate(clk);
846 break;
847 }
848 return -ENOENT;
849 }
850
851 debug("clock %lu has rate %lu\n", id, rate);
852 return rate;
853}
854
855static ulong meson_clk_get_rate(struct clk *clk)
856{
857 return meson_clk_get_rate_by_id(clk, clk->id);
858}
859
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200860static ulong meson_pcie_pll_set_rate(struct clk *clk, ulong rate)
861{
862 struct meson_clk *priv = dev_get_priv(clk->dev);
863
864 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x20090496);
865 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x30090496);
866 regmap_write(priv->map, HHI_PCIE_PLL_CNTL1, 0x00000000);
867 regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001100);
868 regmap_write(priv->map, HHI_PCIE_PLL_CNTL3, 0x10058e00);
869 regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x000100c0);
870 regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000048);
871 regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000068);
872 udelay(20);
873 regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x008100c0);
874 udelay(10);
875 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x34090496);
876 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x14090496);
877 udelay(10);
878 regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001000);
879 regmap_update_bits(priv->map, HHI_PCIE_PLL_CNTL0,
880 0x1f << 16, 9 << 16);
881
882 return 100000000;
883}
884
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200885static int meson_clk_set_parent(struct clk *clk, struct clk *parent)
886{
887 return meson_mux_set_parent(clk, clk->id, parent->id);
888}
889
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200890static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
891 ulong rate, ulong current_rate)
892{
893 if (current_rate == rate)
894 return 0;
895
896 switch (id) {
897 /* Fixed clocks */
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200898 case CLKID_FIXED_PLL:
899 case CLKID_SYS_PLL:
900 case CLKID_FCLK_DIV2:
901 case CLKID_FCLK_DIV3:
902 case CLKID_FCLK_DIV4:
903 case CLKID_FCLK_DIV5:
904 case CLKID_FCLK_DIV7:
905 case CLKID_MPLL0:
906 case CLKID_MPLL1:
907 case CLKID_MPLL2:
908 case CLKID_CLK81:
909 if (current_rate != rate)
910 return -EINVAL;
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200911 case CLKID_PCIE_PLL:
912 return meson_pcie_pll_set_rate(clk, rate);
913
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200914 return 0;
915 case CLKID_VPU:
916 return meson_clk_set_rate_by_id(clk,
917 meson_mux_get_parent(clk, CLKID_VPU), rate,
918 current_rate);
919 case CLKID_VAPB:
920 case CLKID_VAPB_SEL:
921 return meson_clk_set_rate_by_id(clk,
922 meson_mux_get_parent(clk, CLKID_VAPB_SEL),
923 rate, current_rate);
924 case CLKID_VPU_0:
925 return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate,
926 current_rate);
927 case CLKID_VPU_1:
928 return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate,
929 current_rate);
930 case CLKID_VAPB_0:
931 return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate,
932 current_rate);
933 case CLKID_VAPB_1:
934 return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate,
935 current_rate);
936 case CLKID_VPU_0_DIV:
937 case CLKID_VPU_1_DIV:
938 case CLKID_VAPB_0_DIV:
939 case CLKID_VAPB_1_DIV:
940 case CLKID_HDMI_DIV:
941 return meson_div_set_rate(clk, id, rate, current_rate);
942 case CLKID_HDMI:
943 return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV,
944 rate, current_rate);
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200945 default:
946 return -ENOENT;
947 }
948
949 return -EINVAL;
950}
951
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200952static ulong meson_clk_set_rate(struct clk *clk, ulong rate)
953{
954 ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id);
955 int ret;
956
957 if (IS_ERR_VALUE(current_rate))
958 return current_rate;
959
960 debug("%s: setting rate of %ld from %ld to %ld\n",
961 __func__, clk->id, current_rate, rate);
962
963 ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate);
964 if (IS_ERR_VALUE(ret))
965 return ret;
966
967 debug("clock %lu has new rate %lu\n", clk->id,
968 meson_clk_get_rate_by_id(clk, clk->id));
969
970 return 0;
971}
972
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100973static int meson_clk_probe(struct udevice *dev)
974{
975 struct meson_clk *priv = dev_get_priv(dev);
976
977 priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node);
978 if (IS_ERR(priv->map))
979 return PTR_ERR(priv->map);
980
Jerome Brunet01c89ea2020-03-05 12:12:37 +0100981 /*
982 * Depending on the boot src, the state of the MMC clock might
983 * be different. Reset it to make sure we won't get stuck
984 */
985 regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0);
986 regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0);
987
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100988 debug("meson-clk-g12a: probed\n");
989
990 return 0;
991}
992
993static struct clk_ops meson_clk_ops = {
994 .disable = meson_clk_disable,
995 .enable = meson_clk_enable,
996 .get_rate = meson_clk_get_rate,
Neil Armstrong4371b9c2019-08-30 14:09:22 +0200997 .set_parent = meson_clk_set_parent,
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200998 .set_rate = meson_clk_set_rate,
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100999};
1000
1001static const struct udevice_id meson_clk_ids[] = {
1002 { .compatible = "amlogic,g12a-clkc" },
Mark Kettenisb670a5d2019-08-27 23:06:28 +02001003 { .compatible = "amlogic,g12b-clkc" },
Neil Armstrong3e448bd2019-10-11 17:33:53 +02001004 { .compatible = "amlogic,sm1-clkc" },
Jerome Brunetd03f5f02019-02-11 16:45:01 +01001005 { }
1006};
1007
1008U_BOOT_DRIVER(meson_clk_g12a) = {
1009 .name = "meson_clk_g12a",
1010 .id = UCLASS_CLK,
1011 .of_match = meson_clk_ids,
1012 .priv_auto_alloc_size = sizeof(struct meson_clk),
1013 .ops = &meson_clk_ops,
1014 .probe = meson_clk_probe,
1015};