xref: /openbsd-src/sys/dev/fdt/imxccm.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
1 /* $OpenBSD: imxccm.c,v 1.11 2018/08/20 16:48:03 patrick Exp $ */
2 /*
3  * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
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/queue.h>
21 #include <sys/malloc.h>
22 #include <sys/sysctl.h>
23 #include <sys/device.h>
24 #include <sys/evcount.h>
25 #include <sys/socket.h>
26 #include <sys/timeout.h>
27 
28 #include <machine/intr.h>
29 #include <machine/bus.h>
30 #include <machine/fdt.h>
31 
32 #include <dev/ofw/openfirm.h>
33 #include <dev/ofw/ofw_clock.h>
34 #include <dev/ofw/ofw_misc.h>
35 #include <dev/ofw/ofw_regulator.h>
36 #include <dev/ofw/fdt.h>
37 
38 #include <dev/fdt/imxanatopvar.h>
39 
40 /* registers */
41 #define CCM_CCR		0x00
42 #define CCM_CCDR	0x04
43 #define CCM_CSR		0x08
44 #define CCM_CCSR	0x0c
45 #define CCM_CACRR	0x10
46 #define CCM_CBCDR	0x14
47 #define CCM_CBCMR	0x18
48 #define CCM_CSCMR1	0x1c
49 #define CCM_CSCMR2	0x20
50 #define CCM_CSCDR1	0x24
51 #define CCM_CS1CDR	0x28
52 #define CCM_CS2CDR	0x2c
53 #define CCM_CDCDR	0x30
54 #define CCM_CHSCCDR	0x34
55 #define CCM_CSCDR2	0x38
56 #define CCM_CSCDR3	0x3c
57 #define CCM_CSCDR4	0x40
58 #define CCM_CDHIPR	0x48
59 #define CCM_CDCR	0x4c
60 #define CCM_CTOR	0x50
61 #define CCM_CLPCR	0x54
62 #define CCM_CISR	0x58
63 #define CCM_CIMR	0x5c
64 #define CCM_CCOSR	0x60
65 #define CCM_CGPR	0x64
66 #define CCM_CCGR0	0x68
67 #define CCM_CCGR1	0x6c
68 #define CCM_CCGR2	0x70
69 #define CCM_CCGR3	0x74
70 #define CCM_CCGR4	0x78
71 #define CCM_CCGR5	0x7c
72 #define CCM_CCGR6	0x80
73 #define CCM_CCGR7	0x84
74 #define CCM_CMEOR	0x88
75 
76 /* bits and bytes */
77 #define CCM_CCSR_PLL3_SW_CLK_SEL		(1 << 0)
78 #define CCM_CCSR_PLL2_SW_CLK_SEL		(1 << 1)
79 #define CCM_CCSR_PLL1_SW_CLK_SEL		(1 << 2)
80 #define CCM_CCSR_STEP_SEL			(1 << 8)
81 #define CCM_CBCDR_IPG_PODF_SHIFT		8
82 #define CCM_CBCDR_IPG_PODF_MASK			0x3
83 #define CCM_CBCDR_AHB_PODF_SHIFT		10
84 #define CCM_CBCDR_AHB_PODF_MASK			0x7
85 #define CCM_CBCDR_PERIPH_CLK_SEL_SHIFT		25
86 #define CCM_CBCDR_PERIPH_CLK_SEL_MASK		0x1
87 #define CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT		12
88 #define CCM_CBCMR_PERIPH_CLK2_SEL_MASK		0x3
89 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT	18
90 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK	0x3
91 #define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x)	((x) + 15)
92 #define CCM_CSCDR1_USDHCx_CLK_SEL_MASK		0x1
93 #define CCM_CSCDR1_USDHCx_PODF_MASK		0x7
94 #define CCM_CSCDR1_UART_PODF_MASK		0x7
95 #define CCM_CSCDR2_ECSPI_PODF_SHIFT		19
96 #define CCM_CSCDR2_ECSPI_PODF_MASK		0x7
97 #define CCM_CCGR1_ENET				(3 << 10)
98 #define CCM_CCGR4_125M_PCIE			(3 << 0)
99 #define CCM_CCGR5_100M_SATA			(3 << 4)
100 #define CCM_CSCMR1_PERCLK_CLK_PODF_MASK		0x1f
101 #define CCM_CSCMR1_PERCLK_CLK_SEL_MASK		(1 << 6)
102 
103 /* Analog registers */
104 #define CCM_ANALOG_PLL_USB1			0x0010
105 #define CCM_ANALOG_PLL_USB1_SET			0x0014
106 #define CCM_ANALOG_PLL_USB1_CLR			0x0018
107 #define  CCM_ANALOG_PLL_USB1_LOCK		(1U << 31)
108 #define  CCM_ANALOG_PLL_USB1_BYPASS		(1 << 16)
109 #define  CCM_ANALOG_PLL_USB1_ENABLE		(1 << 13)
110 #define  CCM_ANALOG_PLL_USB1_POWER		(1 << 12)
111 #define  CCM_ANALOG_PLL_USB1_EN_USB_CLKS	(1 << 6)
112 #define CCM_ANALOG_PLL_USB2			0x0020
113 #define CCM_ANALOG_PLL_USB2_SET			0x0024
114 #define CCM_ANALOG_PLL_USB2_CLR			0x0028
115 #define  CCM_ANALOG_PLL_USB2_LOCK		(1U << 31)
116 #define  CCM_ANALOG_PLL_USB2_BYPASS		(1 << 16)
117 #define  CCM_ANALOG_PLL_USB2_ENABLE		(1 << 13)
118 #define  CCM_ANALOG_PLL_USB2_POWER		(1 << 12)
119 #define  CCM_ANALOG_PLL_USB2_EN_USB_CLKS	(1 << 6)
120 #define CCM_ANALOG_PLL_ENET			0x00e0
121 #define CCM_ANALOG_PLL_ENET_SET			0x00e4
122 #define CCM_ANALOG_PLL_ENET_CLR			0x00e8
123 #define  CCM_ANALOG_PLL_ENET_LOCK		(1U << 31)
124 #define  CCM_ANALOG_PLL_ENET_ENABLE_100M	(1 << 20) /* i.MX6 */
125 #define  CCM_ANALOG_PLL_ENET_BYPASS		(1 << 16)
126 #define  CCM_ANALOG_PLL_ENET_ENABLE		(1 << 13) /* i.MX6 */
127 #define  CCM_ANALOG_PLL_ENET_POWERDOWN		(1 << 12) /* i.MX6 */
128 #define  CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ	(1 << 10) /* i.MX7 */
129 
130 /* Frac PLL */
131 #define CCM_FRAC_IMX8M_ARM_PLL0			0x28
132 #define CCM_FRAC_IMX8M_ARM_PLL1			0x2c
133 #define  CCM_FRAC_PLL_LOCK				(1 << 31)
134 #define  CCM_FRAC_PLL_ENABLE				(1 << 21)
135 #define  CCM_FRAC_PLL_POWERDOWN				(1 << 19)
136 #define  CCM_FRAC_PLL_REFCLK_SEL_SHIFT			16
137 #define  CCM_FRAC_PLL_REFCLK_SEL_MASK			0x3
138 #define  CCM_FRAC_PLL_LOCK_SEL				(1 << 15)
139 #define  CCM_FRAC_PLL_BYPASS				(1 << 14)
140 #define  CCM_FRAC_PLL_COUNTCLK_SEL			(1 << 13)
141 #define  CCM_FRAC_PLL_NEWDIV_VAL			(1 << 12)
142 #define  CCM_FRAC_PLL_NEWDIV_ACK			(1 << 11)
143 #define  CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT		5
144 #define  CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK		0x3f
145 #define  CCM_FRAC_PLL_OUTPUT_DIV_VAL_SHIFT		0
146 #define  CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK		0x1f
147 #define  CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT		7
148 #define  CCM_FRAC_PLL_FRAC_DIV_CTL_MASK			0x1ffffff
149 #define  CCM_FRAC_PLL_INT_DIV_CTL_SHIFT			0
150 #define  CCM_FRAC_PLL_INT_DIV_CTL_MASK			0x7f
151 #define  CCM_FRAC_PLL_DENOM				(1 << 24)
152 #define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG		0x78
153 #define  CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT	20
154 #define  CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK		0x7
155 
156 #define HCLK_FREQ				24000000
157 #define PLL3_60M				60000000
158 #define PLL3_80M				80000000
159 
160 #define HREAD4(sc, reg)							\
161 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
162 #define HWRITE4(sc, reg, val)						\
163 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
164 #define HSET4(sc, reg, bits)						\
165 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
166 #define HCLR4(sc, reg, bits)						\
167 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
168 
169 struct imxccm_gate {
170 	uint16_t reg;
171 	uint8_t pos;
172 	uint16_t parent;
173 };
174 
175 struct imxccm_divider {
176 	uint16_t reg;
177 	uint16_t shift;
178 	uint16_t mask;
179 	uint16_t parent;
180 	uint16_t fixed;
181 };
182 
183 struct imxccm_mux {
184 	uint16_t reg;
185 	uint16_t shift;
186 	uint16_t mask;
187 };
188 
189 #include "imxccm_clocks.h"
190 
191 struct imxccm_softc {
192 	struct device		sc_dev;
193 	bus_space_tag_t		sc_iot;
194 	bus_space_handle_t	sc_ioh;
195 	int			sc_node;
196 	uint32_t		sc_phandle;
197 
198 	struct regmap		*sc_anatop;
199 
200 	struct imxccm_gate	*sc_gates;
201 	int			sc_ngates;
202 	struct imxccm_divider	*sc_divs;
203 	int			sc_ndivs;
204 	struct imxccm_mux	*sc_muxs;
205 	int			sc_nmuxs;
206 	struct clock_device	sc_cd;
207 };
208 
209 int	imxccm_match(struct device *, void *, void *);
210 void	imxccm_attach(struct device *parent, struct device *self, void *args);
211 
212 struct cfattach	imxccm_ca = {
213 	sizeof (struct imxccm_softc), imxccm_match, imxccm_attach
214 };
215 
216 struct cfdriver imxccm_cd = {
217 	NULL, "imxccm", DV_DULL
218 };
219 
220 uint32_t imxccm_get_armclk(struct imxccm_softc *);
221 void imxccm_armclk_set_parent(struct imxccm_softc *, enum imxanatop_clocks);
222 uint32_t imxccm_get_usdhx(struct imxccm_softc *, int x);
223 uint32_t imxccm_get_periphclk(struct imxccm_softc *);
224 uint32_t imxccm_get_ahbclk(struct imxccm_softc *);
225 uint32_t imxccm_get_ipgclk(struct imxccm_softc *);
226 uint32_t imxccm_get_ipg_perclk(struct imxccm_softc *);
227 uint32_t imxccm_get_uartclk(struct imxccm_softc *);
228 uint32_t imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t);
229 uint32_t imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t);
230 uint32_t imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t);
231 uint32_t imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t);
232 uint32_t imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t);
233 uint32_t imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t);
234 void imxccm_enable(void *, uint32_t *, int);
235 uint32_t imxccm_get_frequency(void *, uint32_t *);
236 int imxccm_set_frequency(void *, uint32_t *, uint32_t);
237 int imxccm_set_parent(void *, uint32_t *, uint32_t *);
238 
239 int
240 imxccm_match(struct device *parent, void *match, void *aux)
241 {
242 	struct fdt_attach_args *faa = aux;
243 
244 	return (OF_is_compatible(faa->fa_node, "fsl,imx6q-ccm") ||
245 	    OF_is_compatible(faa->fa_node, "fsl,imx6sl-ccm") ||
246 	    OF_is_compatible(faa->fa_node, "fsl,imx6sx-ccm") ||
247 	    OF_is_compatible(faa->fa_node, "fsl,imx6ul-ccm") ||
248 	    OF_is_compatible(faa->fa_node, "fsl,imx7d-ccm") ||
249 	    OF_is_compatible(faa->fa_node, "fsl,imx8mq-ccm"));
250 }
251 
252 void
253 imxccm_attach(struct device *parent, struct device *self, void *aux)
254 {
255 	struct imxccm_softc *sc = (struct imxccm_softc *)self;
256 	struct fdt_attach_args *faa = aux;
257 
258 	KASSERT(faa->fa_nreg >= 1);
259 
260 	sc->sc_node = faa->fa_node;
261 	sc->sc_iot = faa->fa_iot;
262 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
263 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
264 		panic("%s: bus_space_map failed!", __func__);
265 
266 	sc->sc_phandle = OF_getpropint(sc->sc_node, "phandle", 0);
267 
268 	if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-ccm")) {
269 		sc->sc_anatop = regmap_bycompatible("fsl,imx8mq-anatop");
270 		KASSERT(sc->sc_anatop != NULL);
271 		sc->sc_gates = imx8mq_gates;
272 		sc->sc_ngates = nitems(imx8mq_gates);
273 		sc->sc_divs = imx8mq_divs;
274 		sc->sc_ndivs = nitems(imx8mq_divs);
275 		sc->sc_muxs = imx8mq_muxs;
276 		sc->sc_nmuxs = nitems(imx8mq_muxs);
277 	} else if (OF_is_compatible(sc->sc_node, "fsl,imx7d-ccm")) {
278 		sc->sc_gates = imx7d_gates;
279 		sc->sc_ngates = nitems(imx7d_gates);
280 		sc->sc_divs = imx7d_divs;
281 		sc->sc_ndivs = nitems(imx7d_divs);
282 		sc->sc_muxs = imx7d_muxs;
283 		sc->sc_nmuxs = nitems(imx7d_muxs);
284 	} else if (OF_is_compatible(sc->sc_node, "fsl,imx6ul-ccm")) {
285 		sc->sc_gates = imx6ul_gates;
286 		sc->sc_ngates = nitems(imx6ul_gates);
287 	} else {
288 		sc->sc_gates = imx6_gates;
289 		sc->sc_ngates = nitems(imx6_gates);
290 	}
291 
292 	printf("\n");
293 
294 	sc->sc_cd.cd_node = faa->fa_node;
295 	sc->sc_cd.cd_cookie = sc;
296 	sc->sc_cd.cd_enable = imxccm_enable;
297 	sc->sc_cd.cd_get_frequency = imxccm_get_frequency;
298 	sc->sc_cd.cd_set_frequency = imxccm_set_frequency;
299 	sc->sc_cd.cd_set_parent = imxccm_set_parent;
300 	clock_register(&sc->sc_cd);
301 }
302 
303 uint32_t
304 imxccm_get_armclk(struct imxccm_softc *sc)
305 {
306 	uint32_t ccsr = HREAD4(sc, CCM_CCSR);
307 
308 	if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL))
309 		return imxanatop_decode_pll(ARM_PLL1, HCLK_FREQ);
310 	else if (ccsr & CCM_CCSR_STEP_SEL)
311 		return imxanatop_get_pll2_pfd(2);
312 	else
313 		return HCLK_FREQ;
314 }
315 
316 void
317 imxccm_armclk_set_parent(struct imxccm_softc *sc, enum imxanatop_clocks clock)
318 {
319 	switch (clock)
320 	{
321 	case ARM_PLL1:
322 		/* jump onto pll1 */
323 		HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
324 		/* put step clk on OSC, power saving */
325 		HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
326 		break;
327 	case OSC:
328 		/* put step clk on OSC */
329 		HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
330 		/* jump onto step clk */
331 		HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
332 		break;
333 	case SYS_PLL2_PFD2:
334 		/* put step clk on pll2-pfd2 400 MHz */
335 		HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
336 		/* jump onto step clk */
337 		HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
338 		break;
339 	default:
340 		panic("%s: parent not possible for arm clk", __func__);
341 	}
342 }
343 
344 uint32_t
345 imxccm_get_ecspiclk(struct imxccm_softc *sc)
346 {
347 	uint32_t clkroot = PLL3_60M;
348 	uint32_t podf = HREAD4(sc, CCM_CSCDR2);
349 
350 	podf >>= CCM_CSCDR2_ECSPI_PODF_SHIFT;
351 	podf &= CCM_CSCDR2_ECSPI_PODF_MASK;
352 
353 	return clkroot / (podf + 1);
354 }
355 
356 unsigned int
357 imxccm_get_usdhx(struct imxccm_softc *sc, int x)
358 {
359 	uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
360 	uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1);
361 	uint32_t podf, clkroot;
362 
363 	// Odd bitsetting. Damn you.
364 	if (x == 1)
365 		podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK);
366 	else
367 		podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK);
368 
369 	if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x)))
370 		clkroot = imxanatop_get_pll2_pfd(0); // 352 MHz
371 	else
372 		clkroot = imxanatop_get_pll2_pfd(2); // 396 MHz
373 
374 	return clkroot / (podf + 1);
375 }
376 
377 uint32_t
378 imxccm_get_uartclk(struct imxccm_softc *sc)
379 {
380 	uint32_t clkroot = PLL3_80M;
381 	uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK;
382 
383 	return clkroot / (podf + 1);
384 }
385 
386 uint32_t
387 imxccm_get_periphclk(struct imxccm_softc *sc)
388 {
389 	if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT)
390 		    & CCM_CBCDR_PERIPH_CLK_SEL_MASK) {
391 		switch((HREAD4(sc, CCM_CBCMR)
392 		    >> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) {
393 		case 0:
394 			return imxanatop_decode_pll(USB1_PLL3, HCLK_FREQ);
395 		case 1:
396 		case 2:
397 			return HCLK_FREQ;
398 		default:
399 			return 0;
400 		}
401 
402 	} else {
403 		switch((HREAD4(sc, CCM_CBCMR)
404 		    >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) {
405 		default:
406 		case 0:
407 			return imxanatop_decode_pll(SYS_PLL2, HCLK_FREQ);
408 		case 1:
409 			return imxanatop_get_pll2_pfd(2); // 396 MHz
410 		case 2:
411 			return imxanatop_get_pll2_pfd(0); // 352 MHz
412 		case 3:
413 			return imxanatop_get_pll2_pfd(2) / 2; // 198 MHz
414 		}
415 	}
416 }
417 
418 uint32_t
419 imxccm_get_ahbclk(struct imxccm_softc *sc)
420 {
421 	uint32_t ahb_podf;
422 
423 	ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT)
424 	    & CCM_CBCDR_AHB_PODF_MASK;
425 	return imxccm_get_periphclk(sc) / (ahb_podf + 1);
426 }
427 
428 uint32_t
429 imxccm_get_ipgclk(struct imxccm_softc *sc)
430 {
431 	uint32_t ipg_podf;
432 
433 	ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT)
434 	    & CCM_CBCDR_IPG_PODF_MASK;
435 	return imxccm_get_ahbclk(sc) / (ipg_podf + 1);
436 }
437 
438 uint32_t
439 imxccm_get_ipg_perclk(struct imxccm_softc *sc)
440 {
441 	uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
442 	uint32_t freq, ipg_podf;
443 
444 	if (sc->sc_gates == imx6ul_gates &&
445 	    cscmr1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK)
446 		freq = HCLK_FREQ;
447 	else
448 		freq = imxccm_get_ipgclk(sc);
449 
450 	ipg_podf = cscmr1 & CCM_CSCMR1_PERCLK_CLK_PODF_MASK;
451 
452 	return freq / (ipg_podf + 1);
453 }
454 
455 void
456 imxccm_imx6_enable_pll_enet(struct imxccm_softc *sc, int on)
457 {
458 	KASSERT(on);
459 
460 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
461 	    CCM_ANALOG_PLL_ENET_POWERDOWN);
462 
463 	/* Wait for the PLL to lock. */
464 	while ((regmap_read_4(sc->sc_anatop,
465 	    CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK) == 0)
466 		;
467 
468 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
469 	    CCM_ANALOG_PLL_ENET_BYPASS);
470 }
471 
472 void
473 imxccm_imx6_enable_pll_usb1(struct imxccm_softc *sc, int on)
474 {
475 	KASSERT(on);
476 
477 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
478 	    CCM_ANALOG_PLL_USB1_POWER);
479 
480 	/* Wait for the PLL to lock. */
481 	while ((regmap_read_4(sc->sc_anatop,
482 	    CCM_ANALOG_PLL_USB1) & CCM_ANALOG_PLL_USB1_LOCK) == 0)
483 		;
484 
485 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_CLR,
486 	    CCM_ANALOG_PLL_USB1_BYPASS);
487 }
488 
489 void
490 imxccm_imx6_enable_pll_usb2(struct imxccm_softc *sc, int on)
491 {
492 	KASSERT(on);
493 
494 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
495 	    CCM_ANALOG_PLL_USB2_POWER);
496 
497 	/* Wait for the PLL to lock. */
498 	while ((regmap_read_4(sc->sc_anatop,
499 	    CCM_ANALOG_PLL_USB2) & CCM_ANALOG_PLL_USB2_LOCK) == 0)
500 		;
501 
502 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_CLR,
503 	    CCM_ANALOG_PLL_USB2_BYPASS);
504 }
505 
506 uint32_t
507 imxccm_imx7d_enet(struct imxccm_softc *sc, uint32_t idx)
508 {
509 	uint32_t mux;
510 
511 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
512 		return 0;
513 
514 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
515 	mux >>= sc->sc_muxs[idx].shift;
516 	mux &= sc->sc_muxs[idx].mask;
517 
518 	switch (mux) {
519 	case 0:
520 		return clock_get_frequency(sc->sc_node, "osc");
521 	case 7:
522 		return 392000000; /* pll_sys_pfd4_clk XXX not fixed */
523 	default:
524 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
525 		return 0;
526 	}
527 }
528 
529 uint32_t
530 imxccm_imx7d_i2c(struct imxccm_softc *sc, uint32_t idx)
531 {
532 	uint32_t mux;
533 
534 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
535 		return 0;
536 
537 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
538 	mux >>= sc->sc_muxs[idx].shift;
539 	mux &= sc->sc_muxs[idx].mask;
540 
541 	switch (mux) {
542 	case 0:
543 		return clock_get_frequency(sc->sc_node, "osc");
544 	case 1:
545 		return 120000000; /* pll_sys_main_120m_clk */
546 	default:
547 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
548 		return 0;
549 	}
550 }
551 
552 uint32_t
553 imxccm_imx7d_uart(struct imxccm_softc *sc, uint32_t idx)
554 {
555 	uint32_t mux;
556 
557 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
558 		return 0;
559 
560 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
561 	mux >>= sc->sc_muxs[idx].shift;
562 	mux &= sc->sc_muxs[idx].mask;
563 
564 	switch (mux) {
565 	case 0:
566 		return clock_get_frequency(sc->sc_node, "osc");
567 	default:
568 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
569 		return 0;
570 	}
571 }
572 
573 uint32_t
574 imxccm_imx7d_usdhc(struct imxccm_softc *sc, uint32_t idx)
575 {
576 	uint32_t mux;
577 
578 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
579 		return 0;
580 
581 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
582 	mux >>= sc->sc_muxs[idx].shift;
583 	mux &= sc->sc_muxs[idx].mask;
584 
585 	switch (mux) {
586 	case 0:
587 		return clock_get_frequency(sc->sc_node, "osc");
588 	case 1:
589 		return 392000000; /* pll_sys_pfd0_392m_clk */
590 	default:
591 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
592 		return 0;
593 	}
594 }
595 
596 uint32_t
597 imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t idx)
598 {
599 	uint32_t mux;
600 
601 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
602 		return 0;
603 
604 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
605 	mux >>= sc->sc_muxs[idx].shift;
606 	mux &= sc->sc_muxs[idx].mask;
607 
608 	switch (mux) {
609 	case 0:
610 		return clock_get_frequency(sc->sc_node, "osc_25m");
611 	case 1:
612 		return 200 * 1000 * 1000; /* sys2_pll_200m */
613 	default:
614 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
615 		return 0;
616 	}
617 }
618 
619 uint32_t
620 imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t idx)
621 {
622 	uint32_t mux;
623 
624 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
625 		return 0;
626 
627 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
628 	mux >>= sc->sc_muxs[idx].shift;
629 	mux &= sc->sc_muxs[idx].mask;
630 
631 	switch (mux) {
632 	case 0:
633 		return clock_get_frequency(sc->sc_node, "osc_25m");
634 	case 1:
635 		return 266 * 1000 * 1000; /* sys1_pll_266m */
636 	default:
637 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
638 		return 0;
639 	}
640 }
641 
642 uint32_t
643 imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t idx)
644 {
645 	uint32_t mux;
646 
647 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
648 		return 0;
649 
650 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
651 	mux >>= sc->sc_muxs[idx].shift;
652 	mux &= sc->sc_muxs[idx].mask;
653 
654 	switch (mux) {
655 	case 0:
656 		return clock_get_frequency(sc->sc_node, "osc_25m");
657 	default:
658 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
659 		return 0;
660 	}
661 }
662 
663 uint32_t
664 imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t idx)
665 {
666 	uint32_t mux;
667 
668 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
669 		return 0;
670 
671 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
672 	mux >>= sc->sc_muxs[idx].shift;
673 	mux &= sc->sc_muxs[idx].mask;
674 
675 	switch (mux) {
676 	case 0:
677 		return clock_get_frequency(sc->sc_node, "osc_25m");
678 	default:
679 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
680 		return 0;
681 	}
682 }
683 
684 uint32_t
685 imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t idx)
686 {
687 	uint32_t mux;
688 
689 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
690 		return 0;
691 
692 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
693 	mux >>= sc->sc_muxs[idx].shift;
694 	mux &= sc->sc_muxs[idx].mask;
695 
696 	switch (mux) {
697 	case 0:
698 		return clock_get_frequency(sc->sc_node, "osc_25m");
699 	case 1:
700 		return 400 * 1000 * 1000; /* sys1_pll_400m */
701 	default:
702 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
703 		return 0;
704 	}
705 }
706 
707 uint32_t
708 imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t idx)
709 {
710 	uint32_t mux;
711 
712 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
713 		return 0;
714 
715 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
716 	mux >>= sc->sc_muxs[idx].shift;
717 	mux &= sc->sc_muxs[idx].mask;
718 
719 	switch (mux) {
720 	case 0:
721 		return clock_get_frequency(sc->sc_node, "osc_25m");
722 	case 1:
723 		if (idx == IMX8MQ_CLK_USB_CORE_REF_SRC ||
724 		    idx == IMX8MQ_CLK_USB_PHY_REF_SRC)
725 			return 100 * 1000 * 1000; /* sys1_pll_100m */
726 		if (idx == IMX8MQ_CLK_USB_BUS_SRC)
727 			return 500 * 1000 * 1000; /* sys2_pll_500m */
728 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
729 		return 0;
730 	default:
731 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
732 		return 0;
733 	}
734 }
735 
736 uint32_t
737 imxccm_imx8mq_get_pll(struct imxccm_softc *sc, uint32_t idx)
738 {
739 	uint32_t divr_val, divq_val, divf_val;
740 	uint32_t divff, divfi;
741 	uint32_t pllout_div;
742 	uint32_t pll0, pll1;
743 	uint32_t freq;
744 	uint32_t mux;
745 
746 	pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
747 
748 	switch (idx) {
749 	case IMX8MQ_ARM_PLL:
750 		pll0 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL0);
751 		pll1 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL1);
752 		pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
753 		pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
754 		break;
755 	default:
756 		printf("%s: 0x%08x\n", __func__, idx);
757 		return 0;
758 	}
759 
760 	if (pll0 & CCM_FRAC_PLL_POWERDOWN)
761 		return 0;
762 
763 	if ((pll0 & CCM_FRAC_PLL_ENABLE) == 0)
764 		return 0;
765 
766 	mux = (pll0 >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
767 	    CCM_FRAC_PLL_REFCLK_SEL_MASK;
768 	switch (mux) {
769 	case 0:
770 		freq = clock_get_frequency(sc->sc_node, "osc_25m");
771 		break;
772 	case 1:
773 	case 2:
774 		freq = clock_get_frequency(sc->sc_node, "osc_27m");
775 		break;
776 	default:
777 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
778 		return 0;
779 	}
780 
781 	if (pll0 & CCM_FRAC_PLL_BYPASS)
782 		return freq;
783 
784 	divr_val = (pll0 >> CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT) &
785 	    CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK;
786 	divq_val = pll0 & CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
787 	divff = (pll1 >> CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT) &
788 	    CCM_FRAC_PLL_FRAC_DIV_CTL_MASK;
789 	divfi = pll1 & CCM_FRAC_PLL_INT_DIV_CTL_MASK;
790 	divf_val = 1 + divfi + divff / CCM_FRAC_PLL_DENOM;
791 
792 	freq = freq / (divr_val + 1) * 8 * divf_val / ((divq_val + 1) * 2);
793 	return freq / (pllout_div + 1);
794 }
795 
796 int
797 imxccm_imx8mq_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq)
798 {
799 	uint64_t divff, divfi, divr;
800 	uint32_t pllout_div;
801 	uint32_t pll0, pll1;
802 	uint32_t mux, reg;
803 	uint64_t pfreq;
804 	int i;
805 
806 	pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
807 
808 	switch (idx) {
809 	case IMX8MQ_ARM_PLL:
810 		pll0 = CCM_FRAC_IMX8M_ARM_PLL0;
811 		pll1 = CCM_FRAC_IMX8M_ARM_PLL1;
812 		pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
813 		pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
814 		/* XXX: Assume fixed divider to ease math. */
815 		KASSERT(pllout_div == 0);
816 		divr = 5;
817 		break;
818 	default:
819 		printf("%s: 0x%08x\n", __func__, idx);
820 		return -1;
821 	}
822 
823 	reg = regmap_read_4(sc->sc_anatop, pll0);
824 	mux = (reg >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
825 	    CCM_FRAC_PLL_REFCLK_SEL_MASK;
826 	switch (mux) {
827 	case 0:
828 		pfreq = clock_get_frequency(sc->sc_node, "osc_25m");
829 		break;
830 	case 1:
831 	case 2:
832 		pfreq = clock_get_frequency(sc->sc_node, "osc_27m");
833 		break;
834 	default:
835 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
836 		return -1;
837 	}
838 
839 	/* Frac divider follows the PLL */
840 	freq *= divr;
841 
842 	/* PLL calculation */
843 	freq *= 2;
844 	pfreq *= 8;
845 	divfi = freq / pfreq;
846 	divff = (uint64_t)(freq - divfi * pfreq);
847 	divff = (divff * CCM_FRAC_PLL_DENOM) / pfreq;
848 
849 	reg = regmap_read_4(sc->sc_anatop, pll1);
850 	reg &= ~(CCM_FRAC_PLL_FRAC_DIV_CTL_MASK << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT);
851 	reg |= divff << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT;
852 	reg &= ~(CCM_FRAC_PLL_INT_DIV_CTL_MASK << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT);
853 	reg |= (divfi - 1) << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT;
854 	regmap_write_4(sc->sc_anatop, pll1, reg);
855 
856 	reg = regmap_read_4(sc->sc_anatop, pll0);
857 	reg &= ~CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
858 	reg &= ~(CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT);
859 	reg |= (divr - 1) << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT;
860 	regmap_write_4(sc->sc_anatop, pll0, reg);
861 
862 	reg = regmap_read_4(sc->sc_anatop, pll0);
863 	reg |= CCM_FRAC_PLL_NEWDIV_VAL;
864 	regmap_write_4(sc->sc_anatop, pll0, reg);
865 
866 	for (i = 0; i < 5000; i++) {
867 		reg = regmap_read_4(sc->sc_anatop, pll0);
868 		if (reg & CCM_FRAC_PLL_BYPASS)
869 			break;
870 		if (reg & CCM_FRAC_PLL_POWERDOWN)
871 			break;
872 		if (reg & CCM_FRAC_PLL_NEWDIV_ACK)
873 			break;
874 		delay(10);
875 	}
876 	if (i == 5000)
877 		printf("%s: timeout\n", __func__);
878 
879 	reg = regmap_read_4(sc->sc_anatop, pll0);
880 	reg &= ~CCM_FRAC_PLL_NEWDIV_VAL;
881 	regmap_write_4(sc->sc_anatop, pll0, reg);
882 
883 	return 0;
884 }
885 
886 void
887 imxccm_enable_parent(struct imxccm_softc *sc, uint32_t parent, int on)
888 {
889 	if (on)
890 		imxccm_enable(sc, &parent, on);
891 }
892 
893 void
894 imxccm_enable(void *cookie, uint32_t *cells, int on)
895 {
896 	struct imxccm_softc *sc = cookie;
897 	uint32_t idx = cells[0], parent;
898 	uint16_t reg;
899 	uint8_t pos;
900 
901 	/* Dummy clock. */
902 	if (idx == 0)
903 		return;
904 
905 	if (sc->sc_gates == imx7d_gates) {
906 		if (sc->sc_anatop == NULL) {
907 			sc->sc_anatop = regmap_bycompatible("fsl,imx7d-anatop");
908 			KASSERT(sc->sc_anatop);
909 		}
910 
911 		switch (idx) {
912 		case IMX7D_PLL_ENET_MAIN_125M_CLK:
913 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_SET,
914 			    CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ);
915 			return;
916 		default:
917 			break;
918 		}
919 	} else if (sc->sc_gates == imx6_gates) {
920 		if (sc->sc_anatop == NULL) {
921 			sc->sc_anatop = regmap_bycompatible("fsl,imx6q-anatop");
922 			KASSERT(sc->sc_anatop);
923 		}
924 
925 		switch (idx) {
926 		case IMX6_CLK_PLL3:
927 			imxccm_imx6_enable_pll_usb1(sc, on);
928 			return;
929 		case IMX6_CLK_PLL6:
930 			imxccm_imx6_enable_pll_enet(sc, on);
931 			return;
932 		case IMX6_CLK_PLL7:
933 			imxccm_imx6_enable_pll_usb2(sc, on);
934 			return;
935 		case IMX6_CLK_PLL3_USB_OTG:
936 			imxccm_enable_parent(sc, IMX6_CLK_PLL3, on);
937 			regmap_write_4(sc->sc_anatop,
938 			    on ? CCM_ANALOG_PLL_USB1_SET : CCM_ANALOG_PLL_USB1_CLR,
939 			    CCM_ANALOG_PLL_USB1_ENABLE);
940 			return;
941 		case IMX6_CLK_PLL6_ENET:
942 			imxccm_enable_parent(sc, IMX6_CLK_PLL6, on);
943 			regmap_write_4(sc->sc_anatop,
944 			    on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
945 			    CCM_ANALOG_PLL_ENET_ENABLE);
946 			return;
947 		case IMX6_CLK_PLL7_USB_HOST:
948 			imxccm_enable_parent(sc, IMX6_CLK_PLL7, on);
949 			regmap_write_4(sc->sc_anatop,
950 			    on ? CCM_ANALOG_PLL_USB2_SET : CCM_ANALOG_PLL_USB2_CLR,
951 			    CCM_ANALOG_PLL_USB2_ENABLE);
952 			return;
953 		case IMX6_CLK_USBPHY1:
954 			/* PLL outputs should alwas be on. */
955 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
956 			    CCM_ANALOG_PLL_USB1_EN_USB_CLKS);
957 			imxccm_enable_parent(sc, IMX6_CLK_PLL3_USB_OTG, on);
958 			return;
959 		case IMX6_CLK_USBPHY2:
960 			/* PLL outputs should alwas be on. */
961 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
962 			    CCM_ANALOG_PLL_USB2_EN_USB_CLKS);
963 			imxccm_enable_parent(sc, IMX6_CLK_PLL7_USB_HOST, on);
964 			return;
965 		case IMX6_CLK_SATA_REF_100:
966 			imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
967 			regmap_write_4(sc->sc_anatop,
968 			   on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
969 			   CCM_ANALOG_PLL_ENET_ENABLE_100M);
970 			return;
971 		case IMX6_CLK_ENET_REF:
972 			imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
973 			return;
974 		case IMX6_CLK_IPG:
975 		case IMX6_CLK_IPG_PER:
976 		case IMX6_CLK_ECSPI_ROOT:
977 			/* always on */
978 			return;
979 		default:
980 			break;
981 		}
982 	}
983 
984 	if (on) {
985 		if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
986 			parent = sc->sc_gates[idx].parent;
987 			imxccm_enable(sc, &parent, on);
988 		}
989 
990 		if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
991 			parent = sc->sc_divs[idx].parent;
992 			imxccm_enable(sc, &parent, on);
993 		}
994 	}
995 
996 	if ((idx < sc->sc_ndivs && sc->sc_divs[idx].reg != 0) ||
997 	    (idx < sc->sc_nmuxs && sc->sc_muxs[idx].reg != 0))
998 		return;
999 
1000 	if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) {
1001 		printf("%s: 0x%08x\n", __func__, idx);
1002 		return;
1003 	}
1004 
1005 	reg = sc->sc_gates[idx].reg;
1006 	pos = sc->sc_gates[idx].pos;
1007 
1008 	if (on)
1009 		HSET4(sc, reg, 0x3 << (2 * pos));
1010 	else
1011 		HCLR4(sc, reg, 0x3 << (2 * pos));
1012 }
1013 
1014 uint32_t
1015 imxccm_get_frequency(void *cookie, uint32_t *cells)
1016 {
1017 	struct imxccm_softc *sc = cookie;
1018 	uint32_t idx = cells[0];
1019 	uint32_t div, parent;
1020 
1021 	/* Dummy clock. */
1022 	if (idx == 0)
1023 		return 0;
1024 
1025 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
1026 		parent = sc->sc_gates[idx].parent;
1027 		return imxccm_get_frequency(sc, &parent);
1028 	}
1029 
1030 	if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
1031 		div = HREAD4(sc, sc->sc_divs[idx].reg);
1032 		div = div >> sc->sc_divs[idx].shift;
1033 		div = div & sc->sc_divs[idx].mask;
1034 		parent = sc->sc_divs[idx].parent;
1035 		return imxccm_get_frequency(sc, &parent) / (div + 1);
1036 	}
1037 
1038 	if (sc->sc_gates == imx8mq_gates) {
1039 		switch (idx) {
1040 		case IMX8MQ_ARM_PLL:
1041 			return imxccm_imx8mq_get_pll(sc, idx);
1042 		case IMX8MQ_CLK_A53_SRC:
1043 			parent = IMX8MQ_ARM_PLL;
1044 			return imxccm_get_frequency(sc, &parent);
1045 		case IMX8MQ_CLK_ENET_AXI_SRC:
1046 			return imxccm_imx8mq_enet(sc, idx);
1047 		case IMX8MQ_CLK_I2C1_SRC:
1048 		case IMX8MQ_CLK_I2C2_SRC:
1049 		case IMX8MQ_CLK_I2C3_SRC:
1050 		case IMX8MQ_CLK_I2C4_SRC:
1051 			return imxccm_imx8mq_i2c(sc, idx);
1052 		case IMX8MQ_CLK_UART1_SRC:
1053 		case IMX8MQ_CLK_UART2_SRC:
1054 		case IMX8MQ_CLK_UART3_SRC:
1055 		case IMX8MQ_CLK_UART4_SRC:
1056 			return imxccm_imx8mq_uart(sc, idx);
1057 		case IMX8MQ_CLK_USDHC1_SRC:
1058 		case IMX8MQ_CLK_USDHC2_SRC:
1059 			return imxccm_imx8mq_usdhc(sc, idx);
1060 		case IMX8MQ_CLK_USB_BUS_SRC:
1061 		case IMX8MQ_CLK_USB_CORE_REF_SRC:
1062 		case IMX8MQ_CLK_USB_PHY_REF_SRC:
1063 			return imxccm_imx8mq_usb(sc, idx);
1064 		case IMX8MQ_CLK_ECSPI1_SRC:
1065 		case IMX8MQ_CLK_ECSPI2_SRC:
1066 		case IMX8MQ_CLK_ECSPI3_SRC:
1067 			return imxccm_imx8mq_ecspi(sc, idx);
1068 		}
1069 	} else if (sc->sc_gates == imx7d_gates) {
1070 		switch (idx) {
1071 		case IMX7D_ENET_AXI_ROOT_SRC:
1072 			return imxccm_imx7d_enet(sc, idx);
1073 		case IMX7D_I2C1_ROOT_SRC:
1074 		case IMX7D_I2C2_ROOT_SRC:
1075 		case IMX7D_I2C3_ROOT_SRC:
1076 		case IMX7D_I2C4_ROOT_SRC:
1077 			return imxccm_imx7d_i2c(sc, idx);
1078 		case IMX7D_UART1_ROOT_SRC:
1079 		case IMX7D_UART2_ROOT_SRC:
1080 		case IMX7D_UART3_ROOT_SRC:
1081 		case IMX7D_UART4_ROOT_SRC:
1082 		case IMX7D_UART5_ROOT_SRC:
1083 		case IMX7D_UART6_ROOT_SRC:
1084 		case IMX7D_UART7_ROOT_SRC:
1085 			return imxccm_imx7d_uart(sc, idx);
1086 		case IMX7D_USDHC1_ROOT_SRC:
1087 		case IMX7D_USDHC2_ROOT_SRC:
1088 		case IMX7D_USDHC3_ROOT_SRC:
1089 			return imxccm_imx7d_usdhc(sc, idx);
1090 		}
1091 	} else if (sc->sc_gates == imx6ul_gates) {
1092 		switch (idx) {
1093 		case IMX6UL_CLK_ARM:
1094 			return imxccm_get_armclk(sc);
1095 		case IMX6UL_CLK_IPG:
1096 			return imxccm_get_ipgclk(sc);
1097 		case IMX6UL_CLK_PERCLK:
1098 			return imxccm_get_ipg_perclk(sc);
1099 		case IMX6UL_CLK_UART1_SERIAL:
1100 			return imxccm_get_uartclk(sc);
1101 		case IMX6UL_CLK_USDHC1:
1102 		case IMX6UL_CLK_USDHC2:
1103 			return imxccm_get_usdhx(sc, idx - IMX6UL_CLK_USDHC1 + 1);
1104 		}
1105 	} else if (sc->sc_gates == imx6_gates) {
1106 		switch (idx) {
1107 		case IMX6_CLK_AHB:
1108 			return imxccm_get_ahbclk(sc);
1109 		case IMX6_CLK_ARM:
1110 			return imxccm_get_armclk(sc);
1111 		case IMX6_CLK_IPG:
1112 			return imxccm_get_ipgclk(sc);
1113 		case IMX6_CLK_IPG_PER:
1114 			return imxccm_get_ipg_perclk(sc);
1115 		case IMX6_CLK_ECSPI_ROOT:
1116 			return imxccm_get_ecspiclk(sc);
1117 		case IMX6_CLK_UART_SERIAL:
1118 			return imxccm_get_uartclk(sc);
1119 		case IMX6_CLK_USDHC1:
1120 		case IMX6_CLK_USDHC2:
1121 		case IMX6_CLK_USDHC3:
1122 		case IMX6_CLK_USDHC4:
1123 			return imxccm_get_usdhx(sc, idx - IMX6_CLK_USDHC1 + 1);
1124 		}
1125 	}
1126 
1127 	printf("%s: 0x%08x\n", __func__, idx);
1128 	return 0;
1129 }
1130 
1131 int
1132 imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1133 {
1134 	struct imxccm_softc *sc = cookie;
1135 	uint32_t idx = cells[0];
1136 	uint32_t reg, div, parent, parent_freq;
1137 	uint32_t pcells[2];
1138 	int ret;
1139 
1140 	if (sc->sc_divs == imx8mq_divs) {
1141 		switch (idx) {
1142 		case IMX8MQ_CLK_A53_DIV:
1143 			parent = IMX8MQ_CLK_A53_SRC;
1144 			return imxccm_set_frequency(cookie, &parent, freq);
1145 		case IMX8MQ_CLK_A53_SRC:
1146 			pcells[0] = sc->sc_phandle;
1147 			pcells[1] = IMX8MQ_SYS1_PLL_800M;
1148 			ret = imxccm_set_parent(cookie, &idx, pcells);
1149 			if (ret)
1150 				return ret;
1151 			ret = imxccm_imx8mq_set_pll(sc, IMX8MQ_ARM_PLL, freq);
1152 			pcells[0] = sc->sc_phandle;
1153 			pcells[1] = IMX8MQ_ARM_PLL_OUT;
1154 			imxccm_set_parent(cookie, &idx, pcells);
1155 			return ret;
1156 		case IMX8MQ_CLK_USB_BUS_SRC:
1157 		case IMX8MQ_CLK_USB_CORE_REF_SRC:
1158 		case IMX8MQ_CLK_USB_PHY_REF_SRC:
1159 			if (imxccm_get_frequency(sc, cells) != freq)
1160 				break;
1161 			return 0;
1162 		case IMX8MQ_CLK_USDHC1_DIV:
1163 			parent = sc->sc_divs[idx].parent;
1164 			if (imxccm_get_frequency(sc, &parent) != freq)
1165 				break;
1166 			imxccm_enable(cookie, &parent, 1);
1167 			reg = HREAD4(sc, sc->sc_divs[idx].reg);
1168 			reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
1169 			reg |= (0x0 << sc->sc_divs[idx].shift);
1170 			HWRITE4(sc, sc->sc_divs[idx].reg, reg);
1171 			return 0;
1172 		}
1173 	} else if (sc->sc_divs == imx7d_divs) {
1174 		switch (idx) {
1175 		case IMX7D_USDHC1_ROOT_CLK:
1176 		case IMX7D_USDHC2_ROOT_CLK:
1177 		case IMX7D_USDHC3_ROOT_CLK:
1178 			parent = sc->sc_gates[idx].parent;
1179 			return imxccm_set_frequency(sc, &parent, freq);
1180 		case IMX7D_USDHC1_ROOT_DIV:
1181 		case IMX7D_USDHC2_ROOT_DIV:
1182 		case IMX7D_USDHC3_ROOT_DIV:
1183 			parent = sc->sc_divs[idx].parent;
1184 			parent_freq = imxccm_get_frequency(sc, &parent);
1185 			div = 0;
1186 			while (parent_freq / (div + 1) > freq)
1187 				div++;
1188 			reg = HREAD4(sc, sc->sc_divs[idx].reg);
1189 			reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
1190 			reg |= (div << sc->sc_divs[idx].shift);
1191 			HWRITE4(sc, sc->sc_divs[idx].reg, reg);
1192 			return 0;
1193 		}
1194 	}
1195 
1196 	printf("%s: 0x%08x %x\n", __func__, idx, freq);
1197 	return -1;
1198 }
1199 
1200 int
1201 imxccm_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells)
1202 {
1203 	struct imxccm_softc *sc = cookie;
1204 	uint32_t idx = cells[0];
1205 	uint32_t pidx;
1206 	uint32_t mux;
1207 
1208 	if (pcells[0] != sc->sc_phandle) {
1209 		printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, pcells[0]);
1210 		return -1;
1211 	}
1212 
1213 	pidx = pcells[1];
1214 
1215 	if (sc->sc_muxs == imx8mq_muxs) {
1216 		switch (idx) {
1217 		case IMX8MQ_CLK_A53_SRC:
1218 			if (pidx != IMX8MQ_ARM_PLL_OUT &&
1219 			    pidx != IMX8MQ_SYS1_PLL_800M)
1220 				break;
1221 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1222 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1223 			if (pidx == IMX8MQ_ARM_PLL_OUT)
1224 				mux |= (0x1 << sc->sc_muxs[idx].shift);
1225 			if (pidx == IMX8MQ_SYS1_PLL_800M)
1226 				mux |= (0x4 << sc->sc_muxs[idx].shift);
1227 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1228 			return 0;
1229 		case IMX8MQ_CLK_USB_BUS_SRC:
1230 			if (pidx != IMX8MQ_SYS2_PLL_500M)
1231 				break;
1232 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1233 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1234 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1235 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1236 			return 0;
1237 		case IMX8MQ_CLK_USB_CORE_REF_SRC:
1238 		case IMX8MQ_CLK_USB_PHY_REF_SRC:
1239 			if (pidx != IMX8MQ_SYS1_PLL_100M)
1240 				break;
1241 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1242 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1243 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1244 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1245 			return 0;
1246 		}
1247 	}
1248 
1249 	printf("%s: 0x%08x 0x%08x\n", __func__, idx, pidx);
1250 	return -1;
1251 }
1252