blob: 43dac1aa37b89edac406e99993cd52962a5e5151 [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>
17#include "clk_meson.h"
18
19#define XTAL_RATE 24000000
20
21struct meson_clk {
22 struct regmap *map;
23};
24
Neil Armstrongfd6574e2019-05-28 10:50:37 +020025static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
26 ulong rate, ulong current_rate);
Jerome Brunetd03f5f02019-02-11 16:45:01 +010027static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
28
29#define NUM_CLKS 178
30
31static struct meson_gate gates[NUM_CLKS] = {
32 /* Everything Else (EE) domain gates */
33 MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8),
34 MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9),
35 MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13),
36 MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 14),
37 MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25),
38 MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26),
39 MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3),
40 MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16),
Neil Armstrongfd6574e2019-05-28 10:50:37 +020041 MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 25),
42 MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8),
Jerome Brunetd03f5f02019-02-11 16:45:01 +010043
44 /* Peripheral Gates */
45 MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23),
46 MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7),
47};
48
49static int meson_set_gate(struct clk *clk, bool on)
50{
51 struct meson_clk *priv = dev_get_priv(clk->dev);
52 struct meson_gate *gate;
53
54 if (clk->id >= ARRAY_SIZE(gates))
55 return -ENOENT;
56
57 gate = &gates[clk->id];
58
59 if (gate->reg == 0)
60 return 0;
61
62 regmap_update_bits(priv->map, gate->reg,
63 BIT(gate->bit), on ? BIT(gate->bit) : 0);
64
65 return 0;
66}
67
68static int meson_clk_enable(struct clk *clk)
69{
70 return meson_set_gate(clk, true);
71}
72
73static int meson_clk_disable(struct clk *clk)
74{
75 return meson_set_gate(clk, false);
76}
77
78static unsigned long meson_clk81_get_rate(struct clk *clk)
79{
80 struct meson_clk *priv = dev_get_priv(clk->dev);
81 unsigned long parent_rate;
82 uint reg;
83 int parents[] = {
84 -1,
85 -1,
86 CLKID_FCLK_DIV7,
87 CLKID_MPLL1,
88 CLKID_MPLL2,
89 CLKID_FCLK_DIV4,
90 CLKID_FCLK_DIV3,
91 CLKID_FCLK_DIV5
92 };
93
94 /* mux */
95 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
96 reg = (reg >> 12) & 7;
97
98 switch (reg) {
99 case 0:
100 parent_rate = XTAL_RATE;
101 break;
102 case 1:
103 return -ENOENT;
104 default:
105 parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]);
106 }
107
108 /* divider */
109 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
110 reg = reg & ((1 << 7) - 1);
111
112 return parent_rate / reg;
113}
114
115static long mpll_rate_from_params(unsigned long parent_rate,
116 unsigned long sdm,
117 unsigned long n2)
118{
119 unsigned long divisor = (SDM_DEN * n2) + sdm;
120
121 if (n2 < N2_MIN)
122 return -EINVAL;
123
124 return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
125}
126
127static struct parm meson_mpll0_parm[2] = {
128 {HHI_MPLL_CNTL1, 0, 14}, /* psdm */
129 {HHI_MPLL_CNTL1, 20, 9}, /* pn2 */
130};
131
132static struct parm meson_mpll1_parm[2] = {
133 {HHI_MPLL_CNTL3, 0, 14}, /* psdm */
134 {HHI_MPLL_CNTL3, 20, 9}, /* pn2 */
135};
136
137static struct parm meson_mpll2_parm[2] = {
138 {HHI_MPLL_CNTL5, 0, 14}, /* psdm */
139 {HHI_MPLL_CNTL5, 20, 9}, /* pn2 */
140};
141
142/*
143 * MultiPhase Locked Loops are outputs from a PLL with additional frequency
144 * scaling capabilities. MPLL rates are calculated as:
145 *
146 * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
147 */
148static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id)
149{
150 struct meson_clk *priv = dev_get_priv(clk->dev);
151 struct parm *psdm, *pn2;
152 unsigned long sdm, n2;
153 unsigned long parent_rate;
154 uint reg;
155
156 switch (id) {
157 case CLKID_MPLL0:
158 psdm = &meson_mpll0_parm[0];
159 pn2 = &meson_mpll0_parm[1];
160 break;
161 case CLKID_MPLL1:
162 psdm = &meson_mpll1_parm[0];
163 pn2 = &meson_mpll1_parm[1];
164 break;
165 case CLKID_MPLL2:
166 psdm = &meson_mpll2_parm[0];
167 pn2 = &meson_mpll2_parm[1];
168 break;
169 default:
170 return -ENOENT;
171 }
172
173 parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL);
174 if (IS_ERR_VALUE(parent_rate))
175 return parent_rate;
176
177 regmap_read(priv->map, psdm->reg_off, &reg);
178 sdm = PARM_GET(psdm->width, psdm->shift, reg);
179
180 regmap_read(priv->map, pn2->reg_off, &reg);
181 n2 = PARM_GET(pn2->width, pn2->shift, reg);
182
183 return mpll_rate_from_params(parent_rate, sdm, n2);
184}
185
186static struct parm meson_fixed_pll_parm[3] = {
187 {HHI_FIX_PLL_CNTL0, 0, 8}, /* pm */
188 {HHI_FIX_PLL_CNTL0, 10, 5}, /* pn */
189 {HHI_FIX_PLL_CNTL0, 16, 2}, /* pod */
190};
191
192static struct parm meson_sys_pll_parm[3] = {
193 {HHI_SYS_PLL_CNTL0, 0, 8}, /* pm */
194 {HHI_SYS_PLL_CNTL0, 10, 5}, /* pn */
195 {HHI_SYS_PLL_CNTL0, 16, 2}, /* pod */
196};
197
198static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
199{
200 struct meson_clk *priv = dev_get_priv(clk->dev);
201 struct parm *pm, *pn, *pod;
202 unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
203 u16 n, m, od;
204 uint reg;
205
206 /*
207 * FIXME: Between the unit conversion and the missing frac, we know
208 * rate will be slightly off ...
209 */
210
211 switch (id) {
212 case CLKID_FIXED_PLL:
213 pm = &meson_fixed_pll_parm[0];
214 pn = &meson_fixed_pll_parm[1];
215 pod = &meson_fixed_pll_parm[2];
216 break;
217 case CLKID_SYS_PLL:
218 pm = &meson_sys_pll_parm[0];
219 pn = &meson_sys_pll_parm[1];
220 pod = &meson_sys_pll_parm[2];
221 break;
222 default:
223 return -ENOENT;
224 }
225
226 regmap_read(priv->map, pn->reg_off, &reg);
227 n = PARM_GET(pn->width, pn->shift, reg);
228
229 regmap_read(priv->map, pm->reg_off, &reg);
230 m = PARM_GET(pm->width, pm->shift, reg);
231
232 regmap_read(priv->map, pod->reg_off, &reg);
233 od = PARM_GET(pod->width, pod->shift, reg);
234
235 return ((parent_rate_mhz * m / n) >> od) * 1000000;
236}
237
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200238static struct parm meson_pcie_pll_parm[3] = {
239 {HHI_PCIE_PLL_CNTL0, 0, 8}, /* pm */
240 {HHI_PCIE_PLL_CNTL0, 10, 5}, /* pn */
241 {HHI_PCIE_PLL_CNTL0, 16, 5}, /* pod */
242};
243
244static ulong meson_pcie_pll_get_rate(struct clk *clk)
245{
246 struct meson_clk *priv = dev_get_priv(clk->dev);
247 struct parm *pm, *pn, *pod;
248 unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
249 u16 n, m, od;
250 uint reg;
251
252 pm = &meson_pcie_pll_parm[0];
253 pn = &meson_pcie_pll_parm[1];
254 pod = &meson_pcie_pll_parm[2];
255
256 regmap_read(priv->map, pn->reg_off, &reg);
257 n = PARM_GET(pn->width, pn->shift, reg);
258
259 regmap_read(priv->map, pm->reg_off, &reg);
260 m = PARM_GET(pm->width, pm->shift, reg);
261
262 regmap_read(priv->map, pod->reg_off, &reg);
263 od = PARM_GET(pod->width, pod->shift, reg);
264
265 return ((parent_rate_mhz * m / n) / 2 / od / 2) * 1000000;
266}
267
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100268static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
269{
270 ulong rate;
271
272 switch (id) {
273 case CLKID_FIXED_PLL:
274 case CLKID_SYS_PLL:
275 rate = meson_pll_get_rate(clk, id);
276 break;
277 case CLKID_FCLK_DIV2:
278 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2;
279 break;
280 case CLKID_FCLK_DIV3:
281 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3;
282 break;
283 case CLKID_FCLK_DIV4:
284 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4;
285 break;
286 case CLKID_FCLK_DIV5:
287 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5;
288 break;
289 case CLKID_FCLK_DIV7:
290 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7;
291 break;
292 case CLKID_MPLL0:
293 case CLKID_MPLL1:
294 case CLKID_MPLL2:
295 rate = meson_mpll_get_rate(clk, id);
296 break;
297 case CLKID_CLK81:
298 rate = meson_clk81_get_rate(clk);
299 break;
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200300 case CLKID_PCIE_PLL:
301 rate = meson_pcie_pll_get_rate(clk);
302 break;
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100303 default:
304 if (gates[id].reg != 0) {
305 /* a clock gate */
306 rate = meson_clk81_get_rate(clk);
307 break;
308 }
309 return -ENOENT;
310 }
311
312 debug("clock %lu has rate %lu\n", id, rate);
313 return rate;
314}
315
316static ulong meson_clk_get_rate(struct clk *clk)
317{
318 return meson_clk_get_rate_by_id(clk, clk->id);
319}
320
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200321static ulong meson_pcie_pll_set_rate(struct clk *clk, ulong rate)
322{
323 struct meson_clk *priv = dev_get_priv(clk->dev);
324
325 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x20090496);
326 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x30090496);
327 regmap_write(priv->map, HHI_PCIE_PLL_CNTL1, 0x00000000);
328 regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001100);
329 regmap_write(priv->map, HHI_PCIE_PLL_CNTL3, 0x10058e00);
330 regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x000100c0);
331 regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000048);
332 regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000068);
333 udelay(20);
334 regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x008100c0);
335 udelay(10);
336 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x34090496);
337 regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x14090496);
338 udelay(10);
339 regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001000);
340 regmap_update_bits(priv->map, HHI_PCIE_PLL_CNTL0,
341 0x1f << 16, 9 << 16);
342
343 return 100000000;
344}
345
346static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
347 ulong rate, ulong current_rate)
348{
349 if (current_rate == rate)
350 return 0;
351
352 switch (id) {
353 /* Fixed clocks */
354 case CLKID_PCIE_PLL:
355 return meson_pcie_pll_set_rate(clk, rate);
356
357 default:
358 return -ENOENT;
359 }
360
361 return -EINVAL;
362}
363
364
365static ulong meson_clk_set_rate(struct clk *clk, ulong rate)
366{
367 ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id);
368 int ret;
369
370 if (IS_ERR_VALUE(current_rate))
371 return current_rate;
372
373 debug("%s: setting rate of %ld from %ld to %ld\n",
374 __func__, clk->id, current_rate, rate);
375
376 ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate);
377 if (IS_ERR_VALUE(ret))
378 return ret;
379
380 debug("clock %lu has new rate %lu\n", clk->id,
381 meson_clk_get_rate_by_id(clk, clk->id));
382
383 return 0;
384}
385
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100386static int meson_clk_probe(struct udevice *dev)
387{
388 struct meson_clk *priv = dev_get_priv(dev);
389
390 priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node);
391 if (IS_ERR(priv->map))
392 return PTR_ERR(priv->map);
393
394 debug("meson-clk-g12a: probed\n");
395
396 return 0;
397}
398
399static struct clk_ops meson_clk_ops = {
400 .disable = meson_clk_disable,
401 .enable = meson_clk_enable,
402 .get_rate = meson_clk_get_rate,
Neil Armstrongfd6574e2019-05-28 10:50:37 +0200403 .set_rate = meson_clk_set_rate,
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100404};
405
406static const struct udevice_id meson_clk_ids[] = {
407 { .compatible = "amlogic,g12a-clkc" },
Mark Kettenisb670a5d2019-08-27 23:06:28 +0200408 { .compatible = "amlogic,g12b-clkc" },
Jerome Brunetd03f5f02019-02-11 16:45:01 +0100409 { }
410};
411
412U_BOOT_DRIVER(meson_clk_g12a) = {
413 .name = "meson_clk_g12a",
414 .id = UCLASS_CLK,
415 .of_match = meson_clk_ids,
416 .priv_auto_alloc_size = sizeof(struct meson_clk),
417 .ops = &meson_clk_ops,
418 .probe = meson_clk_probe,
419};