1 /* $OpenBSD: amlclock.c,v 1.15 2023/08/15 08:27:29 miod Exp $ */
2 /*
3 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_clock.h>
28 #include <dev/ofw/ofw_misc.h>
29 #include <dev/ofw/fdt.h>
30
31 /* Clock IDs */
32 #define G12A_SYS_PLL 0
33 #define G12A_FCLK_DIV2 2
34 #define G12A_FCLK_DIV3 3
35 #define G12A_FCLK_DIV4 4
36 #define G12A_FCLK_DIV5 5
37 #define G12A_FCLK_DIV7 6
38 #define G12A_MPLL1 12
39 #define G12A_MPLL2 13
40 #define G12A_I2C 24
41 #define G12A_SD_EMMC_A 33
42 #define G12A_SD_EMMC_B 34
43 #define G12A_SD_EMMC_C 35
44 #define G12A_PCIE_COMB 45
45 #define G12A_PCIE_PHY 48
46 #define G12A_SD_EMMC_A_CLK0 60
47 #define G12A_SD_EMMC_B_CLK0 61
48 #define G12A_SD_EMMC_C_CLK0 62
49 #define G12A_USB 47
50 #define G12A_FCLK_DIV2P5 99
51 #define G12A_CPU_CLK 187
52 #define G12A_PCIE_PLL 201
53 #define G12A_TS 212
54 #define G12B_SYS1_PLL 214
55 #define G12B_CPUB_CLK 224
56
57 /* Registers */
58 #define HHI_PCIE_PLL_CNTL0 0x26
59 #define HHI_PCIE_PLL_CNTL1 0x27
60 #define HHI_PCIE_PLL_CNTL2 0x28
61 #define HHI_PCIE_PLL_CNTL3 0x29
62 #define HHI_PCIE_PLL_CNTL4 0x2a
63 #define HHI_PCIE_PLL_CNTL5 0x2b
64 #define HHI_GCLK_MPEG0 0x50
65 #define HHI_GCLK_MPEG1 0x51
66 #define HHI_MPEG_CLK_CNTL 0x5d
67 #define HHI_TS_CLK_CNTL 0x64
68 #define HHI_SYS_CPU_CLK_CNTL0 0x67
69 #define HHI_SYS_CPU_CLK_DYN_ENABLE (1 << 26)
70 #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT(x) (((x) >> 20) & 0x3f)
71 #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_MASK (0x3f << 20)
72 #define HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_SHIFT 20
73 #define HHI_SYS_CPU_CLK_POSTMUX1 (1 << 18)
74 #define HHI_SYS_CPU_CLK_PREMUX1(x) (((x) >> 16) & 0x3)
75 #define HHI_SYS_CPU_CLK_PREMUX1_MASK (0x3 << 16)
76 #define HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV2 (0x1 << 16)
77 #define HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV3 (0x2 << 16)
78 #define HHI_SYS_CPU_CLK_FINAL_MUX_SEL (1 << 11)
79 #define HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL (1 << 10)
80 #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT(x) (((x) >> 4) & 0x3f)
81 #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_MASK (0x3f << 4)
82 #define HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_SHIFT 4
83 #define HHI_SYS_CPU_CLK_POSTMUX0 (1 << 2)
84 #define HHI_SYS_CPU_CLK_PREMUX0(x) (((x) >> 0) & 0x3)
85 #define HHI_SYS_CPU_CLK_PREMUX0_MASK (0x3 << 0)
86 #define HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV2 (0x1 << 0)
87 #define HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV3 (0x2 << 0)
88 #define HHI_SYS_CPUB_CLK_CNTL 0x82
89 #define HHI_NAND_CLK_CNTL 0x97
90 #define HHI_SD_EMMC_CLK_CNTL 0x99
91 #define HHI_SYS_PLL_CNTL0 0xbd
92 #define HHI_SYS_DPLL_LOCK (1U << 31)
93 #define HHI_SYS_DPLL_RESET (1 << 29)
94 #define HHI_SYS_DPLL_EN (1 << 28)
95 #define HHI_SYS_DPLL_OD(x) (((x) >> 16) & 0x7)
96 #define HHI_SYS_DPLL_OD_MASK (0x7 << 16)
97 #define HHI_SYS_DPLL_OD_SHIFT 16
98 #define HHI_SYS_DPLL_N(x) (((x) >> 10) & 0x1f)
99 #define HHI_SYS_DPLL_N_MASK (0x1f << 10)
100 #define HHI_SYS_DPLL_N_SHIFT 10
101 #define HHI_SYS_DPLL_M(x) (((x) >> 0) & 0xff)
102 #define HHI_SYS_DPLL_M_MASK (0xff << 0)
103 #define HHI_SYS_DPLL_M_SHIFT 0
104 #define HHI_SYS1_PLL_CNTL0 0xe0
105
106 #define HREAD4(sc, reg) \
107 (regmap_read_4((sc)->sc_rm, (reg) << 2))
108 #define HWRITE4(sc, reg, val) \
109 regmap_write_4((sc)->sc_rm, (reg) << 2, (val))
110 #define HSET4(sc, reg, bits) \
111 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
112 #define HCLR4(sc, reg, bits) \
113 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
114
115 struct amlclock_gate {
116 uint8_t reg;
117 uint8_t bit;
118 };
119
120 const struct amlclock_gate aml_g12a_gates[] = {
121 [G12A_I2C] = { HHI_GCLK_MPEG0, 9 },
122 [G12A_SD_EMMC_A] = { HHI_GCLK_MPEG0, 24 },
123 [G12A_SD_EMMC_B] = { HHI_GCLK_MPEG0, 25 },
124 [G12A_SD_EMMC_C] = { HHI_GCLK_MPEG0, 26 },
125 [G12A_PCIE_COMB] = { HHI_GCLK_MPEG1, 24 },
126 [G12A_USB] = { HHI_GCLK_MPEG1, 26 },
127 [G12A_PCIE_PHY] = { HHI_GCLK_MPEG1, 27 },
128
129 [G12A_SD_EMMC_A_CLK0] = { HHI_SD_EMMC_CLK_CNTL, 7 },
130 [G12A_SD_EMMC_B_CLK0] = { HHI_SD_EMMC_CLK_CNTL, 23 },
131 [G12A_SD_EMMC_C_CLK0] = { HHI_NAND_CLK_CNTL, 7 },
132
133 [G12A_TS] = { HHI_TS_CLK_CNTL, 8 },
134 };
135
136 struct amlclock_softc {
137 struct device sc_dev;
138 struct regmap *sc_rm;
139 int sc_node;
140 uint32_t sc_g12b;
141
142 const struct amlclock_gate *sc_gates;
143 int sc_ngates;
144
145 struct clock_device sc_cd;
146 uint32_t sc_xtal;
147 };
148
149 int amlclock_match(struct device *, void *, void *);
150 void amlclock_attach(struct device *, struct device *, void *);
151
152 const struct cfattach amlclock_ca = {
153 sizeof (struct amlclock_softc), amlclock_match, amlclock_attach
154 };
155
156 struct cfdriver amlclock_cd = {
157 NULL, "amlclock", DV_DULL
158 };
159
160 uint32_t amlclock_get_frequency(void *, uint32_t *);
161 int amlclock_set_frequency(void *, uint32_t *, uint32_t);
162 void amlclock_enable(void *, uint32_t *, int);
163
164 int
amlclock_match(struct device * parent,void * match,void * aux)165 amlclock_match(struct device *parent, void *match, void *aux)
166 {
167 struct fdt_attach_args *faa = aux;
168
169 return (OF_is_compatible(faa->fa_node, "amlogic,g12a-clkc") ||
170 OF_is_compatible(faa->fa_node, "amlogic,g12b-clkc") ||
171 OF_is_compatible(faa->fa_node, "amlogic,sm1-clkc"));
172 }
173
174 void
amlclock_attach(struct device * parent,struct device * self,void * aux)175 amlclock_attach(struct device *parent, struct device *self, void *aux)
176 {
177 struct amlclock_softc *sc = (struct amlclock_softc *)self;
178 struct fdt_attach_args *faa = aux;
179
180 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
181 if (sc->sc_rm == NULL) {
182 printf(": no registers\n");
183 return;
184 }
185
186 sc->sc_node = faa->fa_node;
187 printf("\n");
188
189 if (OF_is_compatible(faa->fa_node, "amlogic,g12b-clkc"))
190 sc->sc_g12b = 1;
191
192 sc->sc_gates = aml_g12a_gates;
193 sc->sc_ngates = nitems(aml_g12a_gates);
194
195 sc->sc_xtal = clock_get_frequency(sc->sc_node, "xtal");
196
197 sc->sc_cd.cd_node = faa->fa_node;
198 sc->sc_cd.cd_cookie = sc;
199 sc->sc_cd.cd_get_frequency = amlclock_get_frequency;
200 sc->sc_cd.cd_set_frequency = amlclock_set_frequency;
201 sc->sc_cd.cd_enable = amlclock_enable;
202 clock_register(&sc->sc_cd);
203 }
204
205 uint32_t
amlclock_get_cpu_freq(struct amlclock_softc * sc,bus_size_t offset)206 amlclock_get_cpu_freq(struct amlclock_softc *sc, bus_size_t offset)
207 {
208 uint32_t reg, mux, div;
209 uint32_t idx;
210
211 reg = HREAD4(sc, offset);
212 if (reg & HHI_SYS_CPU_CLK_FINAL_MUX_SEL) {
213 if (sc->sc_g12b && offset == HHI_SYS_CPU_CLK_CNTL0)
214 idx = G12B_SYS1_PLL;
215 else
216 idx = G12A_SYS_PLL;
217 return amlclock_get_frequency(sc, &idx);
218 }
219 if (reg & HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL) {
220 div = (reg & HHI_SYS_CPU_CLK_POSTMUX1) ?
221 (HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT(reg) + 1) : 1;
222 mux = HHI_SYS_CPU_CLK_PREMUX1(reg);
223 } else {
224 div = (reg & HHI_SYS_CPU_CLK_POSTMUX0) ?
225 (HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT(reg) + 1) : 1;
226 mux = HHI_SYS_CPU_CLK_PREMUX0(reg);
227 }
228 switch (mux) {
229 case 0:
230 return sc->sc_xtal / div;
231 case 1:
232 idx = G12A_FCLK_DIV2;
233 break;
234 case 2:
235 idx = G12A_FCLK_DIV3;
236 break;
237 case 3:
238 return 0;
239 }
240 return amlclock_get_frequency(sc, &idx) / div;
241 }
242
243 int
amlclock_set_cpu_freq(struct amlclock_softc * sc,bus_size_t offset,uint32_t freq)244 amlclock_set_cpu_freq(struct amlclock_softc *sc, bus_size_t offset,
245 uint32_t freq)
246 {
247 uint32_t reg, div;
248 uint32_t parent_freq;
249 uint32_t idx;
250
251 /*
252 * For clock frequencies above 1GHz we have to use
253 * SYS_PLL/SYS1_PLL.
254 */
255 reg = HREAD4(sc, offset);
256 if (freq > 1000000000) {
257 /*
258 * Switch to a fixed clock if we're currently using
259 * SYS_PLL/SYS1_PLL. Doesn't really matter which one.
260 */
261 if (reg & HHI_SYS_CPU_CLK_FINAL_MUX_SEL) {
262 reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
263 HWRITE4(sc, offset, reg);
264 delay(100);
265 }
266
267 if (sc->sc_g12b && offset == HHI_SYS_CPU_CLK_CNTL0)
268 idx = G12B_SYS1_PLL;
269 else
270 idx = G12A_SYS_PLL;
271 amlclock_set_frequency(sc, &idx, freq);
272
273 /* Switch to SYS_PLL/SYS1_PLL. */
274 reg |= HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
275 HWRITE4(sc, offset, reg);
276 delay(100);
277
278 return 0;
279 }
280
281 /*
282 * There are two signal paths for frequencies up to 1GHz. If
283 * we're using one, we can program the dividers for the other
284 * one and switch to it. The pre-divider can be either 2 or 3
285 * and can't be bypassed, so take this into account and only
286 * allow frequencies that include such a divider.
287 */
288 div = 2;
289 parent_freq = 2000000000;
290 while (parent_freq / div > freq)
291 div++;
292 while ((div % 2) != 0 && (div % 3) != 0)
293 div++;
294 if (div > 32)
295 return EINVAL;
296 if ((div % 2) == 0) {
297 parent_freq /= 2;
298 div /= 2;
299 } else {
300 parent_freq /= 3;
301 div /= 3;
302 }
303
304 if (reg & HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL) {
305 /* premux0 */
306 reg = HREAD4(sc, offset);
307 reg &= ~HHI_SYS_CPU_CLK_PREMUX0_MASK;
308 if (parent_freq == 1000000000)
309 reg |= HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV2;
310 else
311 reg |= HHI_SYS_CPU_CLK_PREMUX0_FCLK_DIV3;
312 HWRITE4(sc, offset, reg);
313 delay(100);
314
315 /* mux0 divider */
316 HSET4(sc, offset, HHI_SYS_CPU_CLK_DYN_ENABLE);
317 reg = HREAD4(sc, offset);
318 reg &= ~HHI_SYS_CPU_CLK_DYN_ENABLE;
319 reg &= ~HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_MASK;
320 reg |= ((div - 1) << HHI_SYS_CPU_CLK_MUX0_DIVN_TCNT_SHIFT);
321 HWRITE4(sc, offset, reg);
322
323 /* postmux0 */
324 if (div != 1)
325 HSET4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX0);
326 else
327 HCLR4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX0);
328
329 /* final_dyn_mux_sel and final_mux_sel */
330 reg = HREAD4(sc, offset);
331 reg &= ~HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL;
332 reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
333 HWRITE4(sc, offset, reg);
334 delay(100);
335 } else {
336 /* premux1 */
337 reg = HREAD4(sc, offset);
338 reg &= ~HHI_SYS_CPU_CLK_PREMUX1_MASK;
339 if (parent_freq == 1000000000)
340 reg |= HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV2;
341 else
342 reg |= HHI_SYS_CPU_CLK_PREMUX1_FCLK_DIV3;
343 HWRITE4(sc, offset, reg);
344 delay(100);
345
346 /* mux1 divider */
347 HSET4(sc, offset, HHI_SYS_CPU_CLK_DYN_ENABLE);
348 reg = HREAD4(sc, offset);
349 reg &= ~HHI_SYS_CPU_CLK_DYN_ENABLE;
350 reg &= ~HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_MASK;
351 reg |= ((div - 1) << HHI_SYS_CPU_CLK_MUX1_DIVN_TCNT_SHIFT);
352 HWRITE4(sc, offset, reg);
353
354 /* postmux1 */
355 if (div != 1)
356 HSET4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX1);
357 else
358 HCLR4(sc, offset, HHI_SYS_CPU_CLK_POSTMUX1);
359
360 /* final_dyn_mux_sel and final_mux_sel */
361 reg = HREAD4(sc, offset);
362 reg |= HHI_SYS_CPU_CLK_FINAL_DYN_MUX_SEL;
363 reg &= ~HHI_SYS_CPU_CLK_FINAL_MUX_SEL;
364 HWRITE4(sc, offset, reg);
365 delay(100);
366 }
367
368 return 0;
369 }
370
371 int
amlclock_set_pll_freq(struct amlclock_softc * sc,bus_size_t offset,uint32_t freq)372 amlclock_set_pll_freq(struct amlclock_softc *sc, bus_size_t offset,
373 uint32_t freq)
374 {
375 uint32_t reg, div;
376 uint32_t m, n = 1;
377 int timo;
378
379 /*
380 * The multiplier should be between 128 and 255. If
381 * necessary, adjust the divider to achieve this.
382 */
383 div = 1;
384 while ((div * (uint64_t)freq) / sc->sc_xtal < 128)
385 div *= 2;
386 if (div > 128)
387 return EINVAL;
388 m = (div * (uint64_t)freq) / sc->sc_xtal;
389 if (m > 255)
390 return EINVAL;
391
392 HSET4(sc, offset, HHI_SYS_DPLL_RESET);
393 HCLR4(sc, offset, HHI_SYS_DPLL_EN);
394
395 reg = HREAD4(sc, offset);
396 reg &= ~HHI_SYS_DPLL_OD_MASK;
397 reg |= ((fls(div) - 1) << HHI_SYS_DPLL_OD_SHIFT);
398 reg &= ~(HHI_SYS_DPLL_M_MASK | HHI_SYS_DPLL_N_MASK);
399 reg |= (m << HHI_SYS_DPLL_M_SHIFT);
400 reg |= (n << HHI_SYS_DPLL_N_SHIFT);
401 HWRITE4(sc, offset, reg);
402
403 HSET4(sc, offset, HHI_SYS_DPLL_RESET);
404 HSET4(sc, offset, HHI_SYS_DPLL_EN);
405 HCLR4(sc, offset, HHI_SYS_DPLL_RESET);
406
407 for (timo = 24000000; timo > 0; timo--) {
408 if (HREAD4(sc, offset) & HHI_SYS_DPLL_LOCK)
409 return 0;
410 }
411
412 return ETIMEDOUT;
413 }
414
415 uint32_t
amlclock_get_frequency(void * cookie,uint32_t * cells)416 amlclock_get_frequency(void *cookie, uint32_t *cells)
417 {
418 struct amlclock_softc *sc = cookie;
419 uint32_t idx = cells[0];
420 uint32_t reg, mux, div;
421 uint32_t m, n;
422
423 switch (idx) {
424 case G12A_SYS_PLL:
425 reg = HREAD4(sc, HHI_SYS_PLL_CNTL0);
426 div = 1 << HHI_SYS_DPLL_OD(reg);
427 m = HHI_SYS_DPLL_M(reg);
428 n = HHI_SYS_DPLL_N(reg);
429 return (((uint64_t)sc->sc_xtal * m) / n) / div;
430 case G12B_SYS1_PLL:
431 reg = HREAD4(sc, HHI_SYS1_PLL_CNTL0);
432 div = 1 << HHI_SYS_DPLL_OD(reg);
433 m = HHI_SYS_DPLL_M(reg);
434 n = HHI_SYS_DPLL_N(reg);
435 return (((uint64_t)sc->sc_xtal * m) / n) / div;
436 case G12A_FCLK_DIV2:
437 return 1000000000;
438 case G12A_FCLK_DIV3:
439 return 666666666;
440 case G12A_FCLK_DIV4:
441 return 500000000;
442 case G12A_FCLK_DIV5:
443 return 400000000;
444 case G12A_FCLK_DIV7:
445 return 285714285;
446 case G12A_FCLK_DIV2P5:
447 return 800000000;
448
449 case G12A_I2C:
450 reg = HREAD4(sc, HHI_MPEG_CLK_CNTL);
451 mux = (reg >> 12) & 0x7;
452 div = ((reg >> 0) & 0x7f) + 1;
453 switch (mux) {
454 case 0:
455 return sc->sc_xtal / div;
456 case 2:
457 idx = G12A_FCLK_DIV7;
458 break;
459 case 3:
460 idx = G12A_MPLL1;
461 break;
462 case 4:
463 idx = G12A_MPLL2;
464 break;
465 case 5:
466 idx = G12A_FCLK_DIV4;
467 break;
468 case 6:
469 idx = G12A_FCLK_DIV3;
470 break;
471 case 7:
472 idx = G12A_FCLK_DIV5;
473 break;
474 default:
475 goto fail;
476 }
477 return amlclock_get_frequency(sc, &idx) / div;
478 case G12A_SD_EMMC_A_CLK0:
479 reg = HREAD4(sc, HHI_SD_EMMC_CLK_CNTL);
480 mux = (reg >> 9) & 0x7;
481 div = ((reg >> 0) & 0x7f) + 1;
482 switch (mux) {
483 case 0:
484 return sc->sc_xtal / div;
485 case 1:
486 idx = G12A_FCLK_DIV2;
487 break;
488 case 2:
489 idx = G12A_FCLK_DIV3;
490 break;
491 case 3:
492 idx = G12A_FCLK_DIV5;
493 break;
494 case 4:
495 idx = G12A_FCLK_DIV7;
496 break;
497 default:
498 goto fail;
499 }
500 return amlclock_get_frequency(sc, &idx) / div;
501 case G12A_SD_EMMC_B_CLK0:
502 reg = HREAD4(sc, HHI_SD_EMMC_CLK_CNTL);
503 mux = (reg >> 25) & 0x7;
504 div = ((reg >> 16) & 0x7f) + 1;
505 switch (mux) {
506 case 0:
507 return sc->sc_xtal / div;
508 case 1:
509 idx = G12A_FCLK_DIV2;
510 break;
511 case 2:
512 idx = G12A_FCLK_DIV3;
513 break;
514 case 3:
515 idx = G12A_FCLK_DIV5;
516 break;
517 case 4:
518 idx = G12A_FCLK_DIV7;
519 break;
520 default:
521 goto fail;
522 }
523 return amlclock_get_frequency(sc, &idx) / div;
524 case G12A_SD_EMMC_C_CLK0:
525 reg = HREAD4(sc, HHI_NAND_CLK_CNTL);
526 mux = (reg >> 9) & 0x7;
527 div = ((reg >> 0) & 0x7f) + 1;
528 switch (mux) {
529 case 0:
530 return sc->sc_xtal / div;
531 case 1:
532 idx = G12A_FCLK_DIV2;
533 break;
534 case 2:
535 idx = G12A_FCLK_DIV3;
536 break;
537 case 3:
538 idx = G12A_FCLK_DIV5;
539 break;
540 case 4:
541 idx = G12A_FCLK_DIV7;
542 break;
543 default:
544 goto fail;
545 }
546 return amlclock_get_frequency(sc, &idx) / div;
547 case G12A_CPU_CLK:
548 return amlclock_get_cpu_freq(sc, HHI_SYS_CPU_CLK_CNTL0);
549 case G12B_CPUB_CLK:
550 return amlclock_get_cpu_freq(sc, HHI_SYS_CPUB_CLK_CNTL);
551 }
552
553 fail:
554 printf("%s: 0x%08x\n", __func__, idx);
555 return 0;
556 }
557
558 int
amlclock_set_frequency(void * cookie,uint32_t * cells,uint32_t freq)559 amlclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
560 {
561 struct amlclock_softc *sc = cookie;
562 uint32_t idx = cells[0];
563
564 switch (idx) {
565 case G12A_SYS_PLL:
566 return amlclock_set_pll_freq(sc, HHI_SYS_PLL_CNTL0, freq);
567 case G12B_SYS1_PLL:
568 return amlclock_set_pll_freq(sc, HHI_SYS1_PLL_CNTL0, freq);
569 case G12A_PCIE_PLL:
570 /* Fixed at 100 MHz. */
571 if (freq != 100000000)
572 return -1;
573 HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x20090496);
574 HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x30090496);
575 HWRITE4(sc, HHI_PCIE_PLL_CNTL1, 0x00000000);
576 HWRITE4(sc, HHI_PCIE_PLL_CNTL2, 0x00001100);
577 HWRITE4(sc, HHI_PCIE_PLL_CNTL3, 0x10058e00);
578 HWRITE4(sc, HHI_PCIE_PLL_CNTL4, 0x000100c0);
579 HWRITE4(sc, HHI_PCIE_PLL_CNTL5, 0x68000048);
580 HWRITE4(sc, HHI_PCIE_PLL_CNTL5, 0x68000068);
581 delay(20);
582 HWRITE4(sc, HHI_PCIE_PLL_CNTL4, 0x008100c0);
583 delay(10);
584 HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x34090496);
585 HWRITE4(sc, HHI_PCIE_PLL_CNTL0, 0x14090496);
586 delay(10);
587 HWRITE4(sc, HHI_PCIE_PLL_CNTL2, 0x00001000);
588 return 0;
589 case G12A_CPU_CLK:
590 return amlclock_set_cpu_freq(sc, HHI_SYS_CPU_CLK_CNTL0, freq);
591 case G12B_CPUB_CLK:
592 return amlclock_set_cpu_freq(sc, HHI_SYS_CPUB_CLK_CNTL, freq);
593 }
594
595 printf("%s: 0x%08x\n", __func__, idx);
596 return -1;
597 }
598
599 void
amlclock_enable(void * cookie,uint32_t * cells,int on)600 amlclock_enable(void *cookie, uint32_t *cells, int on)
601 {
602 struct amlclock_softc *sc = cookie;
603 uint32_t idx = cells[0];
604
605 if (idx < sc->sc_ngates && sc->sc_gates[idx].reg != 0) {
606 if (on)
607 HSET4(sc, sc->sc_gates[idx].reg,
608 (1U << sc->sc_gates[idx].bit));
609 else
610 HCLR4(sc, sc->sc_gates[idx].reg,
611 (1U << sc->sc_gates[idx].bit));
612 return;
613 }
614
615 switch (idx) {
616 case G12A_FCLK_DIV2:
617 case G12A_PCIE_PLL:
618 /* Already enabled. */
619 return;
620 }
621
622 printf("%s: 0x%08x\n", __func__, idx);
623 }
624