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