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