xref: /openbsd-src/sys/dev/fdt/imxccm.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: imxccm.c,v 1.15 2019/04/01 08:49:35 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 imxccm_divider	*sc_predivs;
207 	int			sc_npredivs;
208 	struct clock_device	sc_cd;
209 };
210 
211 int	imxccm_match(struct device *, void *, void *);
212 void	imxccm_attach(struct device *parent, struct device *self, void *args);
213 
214 struct cfattach	imxccm_ca = {
215 	sizeof (struct imxccm_softc), imxccm_match, imxccm_attach
216 };
217 
218 struct cfdriver imxccm_cd = {
219 	NULL, "imxccm", DV_DULL
220 };
221 
222 uint32_t imxccm_get_armclk(struct imxccm_softc *);
223 void imxccm_armclk_set_parent(struct imxccm_softc *, enum imxanatop_clocks);
224 uint32_t imxccm_get_usdhx(struct imxccm_softc *, int x);
225 uint32_t imxccm_get_periphclk(struct imxccm_softc *);
226 uint32_t imxccm_get_ahbclk(struct imxccm_softc *);
227 uint32_t imxccm_get_ipgclk(struct imxccm_softc *);
228 uint32_t imxccm_get_ipg_perclk(struct imxccm_softc *);
229 uint32_t imxccm_get_uartclk(struct imxccm_softc *);
230 uint32_t imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t);
231 uint32_t imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t);
232 uint32_t imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t);
233 uint32_t imxccm_imx8mq_pwm(struct imxccm_softc *sc, uint32_t);
234 uint32_t imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t);
235 uint32_t imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t);
236 uint32_t imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t);
237 void imxccm_enable(void *, uint32_t *, int);
238 uint32_t imxccm_get_frequency(void *, uint32_t *);
239 int imxccm_set_frequency(void *, uint32_t *, uint32_t);
240 int imxccm_set_parent(void *, uint32_t *, uint32_t *);
241 
242 int
243 imxccm_match(struct device *parent, void *match, void *aux)
244 {
245 	struct fdt_attach_args *faa = aux;
246 
247 	return (OF_is_compatible(faa->fa_node, "fsl,imx6q-ccm") ||
248 	    OF_is_compatible(faa->fa_node, "fsl,imx6sl-ccm") ||
249 	    OF_is_compatible(faa->fa_node, "fsl,imx6sx-ccm") ||
250 	    OF_is_compatible(faa->fa_node, "fsl,imx6ul-ccm") ||
251 	    OF_is_compatible(faa->fa_node, "fsl,imx7d-ccm") ||
252 	    OF_is_compatible(faa->fa_node, "fsl,imx8mq-ccm"));
253 }
254 
255 void
256 imxccm_attach(struct device *parent, struct device *self, void *aux)
257 {
258 	struct imxccm_softc *sc = (struct imxccm_softc *)self;
259 	struct fdt_attach_args *faa = aux;
260 
261 	KASSERT(faa->fa_nreg >= 1);
262 
263 	sc->sc_node = faa->fa_node;
264 	sc->sc_iot = faa->fa_iot;
265 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
266 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
267 		panic("%s: bus_space_map failed!", __func__);
268 
269 	sc->sc_phandle = OF_getpropint(sc->sc_node, "phandle", 0);
270 
271 	if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-ccm")) {
272 		sc->sc_anatop = regmap_bycompatible("fsl,imx8mq-anatop");
273 		KASSERT(sc->sc_anatop != NULL);
274 		sc->sc_gates = imx8mq_gates;
275 		sc->sc_ngates = nitems(imx8mq_gates);
276 		sc->sc_divs = imx8mq_divs;
277 		sc->sc_ndivs = nitems(imx8mq_divs);
278 		sc->sc_muxs = imx8mq_muxs;
279 		sc->sc_nmuxs = nitems(imx8mq_muxs);
280 		sc->sc_predivs = imx8mq_predivs;
281 		sc->sc_npredivs = nitems(imx8mq_predivs);
282 	} else if (OF_is_compatible(sc->sc_node, "fsl,imx7d-ccm")) {
283 		sc->sc_gates = imx7d_gates;
284 		sc->sc_ngates = nitems(imx7d_gates);
285 		sc->sc_divs = imx7d_divs;
286 		sc->sc_ndivs = nitems(imx7d_divs);
287 		sc->sc_muxs = imx7d_muxs;
288 		sc->sc_nmuxs = nitems(imx7d_muxs);
289 	} else if (OF_is_compatible(sc->sc_node, "fsl,imx6ul-ccm")) {
290 		sc->sc_gates = imx6ul_gates;
291 		sc->sc_ngates = nitems(imx6ul_gates);
292 	} else {
293 		sc->sc_gates = imx6_gates;
294 		sc->sc_ngates = nitems(imx6_gates);
295 	}
296 
297 	printf("\n");
298 
299 	sc->sc_cd.cd_node = faa->fa_node;
300 	sc->sc_cd.cd_cookie = sc;
301 	sc->sc_cd.cd_enable = imxccm_enable;
302 	sc->sc_cd.cd_get_frequency = imxccm_get_frequency;
303 	sc->sc_cd.cd_set_frequency = imxccm_set_frequency;
304 	sc->sc_cd.cd_set_parent = imxccm_set_parent;
305 	clock_register(&sc->sc_cd);
306 }
307 
308 uint32_t
309 imxccm_get_armclk(struct imxccm_softc *sc)
310 {
311 	uint32_t ccsr = HREAD4(sc, CCM_CCSR);
312 
313 	if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL))
314 		return imxanatop_decode_pll(ARM_PLL1, HCLK_FREQ);
315 	else if (ccsr & CCM_CCSR_STEP_SEL)
316 		return imxanatop_get_pll2_pfd(2);
317 	else
318 		return HCLK_FREQ;
319 }
320 
321 void
322 imxccm_armclk_set_parent(struct imxccm_softc *sc, enum imxanatop_clocks clock)
323 {
324 	switch (clock)
325 	{
326 	case ARM_PLL1:
327 		/* jump onto pll1 */
328 		HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
329 		/* put step clk on OSC, power saving */
330 		HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
331 		break;
332 	case OSC:
333 		/* put step clk on OSC */
334 		HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
335 		/* jump onto step clk */
336 		HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
337 		break;
338 	case SYS_PLL2_PFD2:
339 		/* put step clk on pll2-pfd2 400 MHz */
340 		HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
341 		/* jump onto step clk */
342 		HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
343 		break;
344 	default:
345 		panic("%s: parent not possible for arm clk", __func__);
346 	}
347 }
348 
349 uint32_t
350 imxccm_get_ecspiclk(struct imxccm_softc *sc)
351 {
352 	uint32_t clkroot = PLL3_60M;
353 	uint32_t podf = HREAD4(sc, CCM_CSCDR2);
354 
355 	podf >>= CCM_CSCDR2_ECSPI_PODF_SHIFT;
356 	podf &= CCM_CSCDR2_ECSPI_PODF_MASK;
357 
358 	return clkroot / (podf + 1);
359 }
360 
361 unsigned int
362 imxccm_get_usdhx(struct imxccm_softc *sc, int x)
363 {
364 	uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
365 	uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1);
366 	uint32_t podf, clkroot;
367 
368 	// Odd bitsetting. Damn you.
369 	if (x == 1)
370 		podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK);
371 	else
372 		podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK);
373 
374 	if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x)))
375 		clkroot = imxanatop_get_pll2_pfd(0); // 352 MHz
376 	else
377 		clkroot = imxanatop_get_pll2_pfd(2); // 396 MHz
378 
379 	return clkroot / (podf + 1);
380 }
381 
382 uint32_t
383 imxccm_get_uartclk(struct imxccm_softc *sc)
384 {
385 	uint32_t clkroot = PLL3_80M;
386 	uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK;
387 
388 	return clkroot / (podf + 1);
389 }
390 
391 uint32_t
392 imxccm_get_periphclk(struct imxccm_softc *sc)
393 {
394 	if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT)
395 		    & CCM_CBCDR_PERIPH_CLK_SEL_MASK) {
396 		switch((HREAD4(sc, CCM_CBCMR)
397 		    >> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) {
398 		case 0:
399 			return imxanatop_decode_pll(USB1_PLL3, HCLK_FREQ);
400 		case 1:
401 		case 2:
402 			return HCLK_FREQ;
403 		default:
404 			return 0;
405 		}
406 
407 	} else {
408 		switch((HREAD4(sc, CCM_CBCMR)
409 		    >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) {
410 		default:
411 		case 0:
412 			return imxanatop_decode_pll(SYS_PLL2, HCLK_FREQ);
413 		case 1:
414 			return imxanatop_get_pll2_pfd(2); // 396 MHz
415 		case 2:
416 			return imxanatop_get_pll2_pfd(0); // 352 MHz
417 		case 3:
418 			return imxanatop_get_pll2_pfd(2) / 2; // 198 MHz
419 		}
420 	}
421 }
422 
423 uint32_t
424 imxccm_get_ahbclk(struct imxccm_softc *sc)
425 {
426 	uint32_t ahb_podf;
427 
428 	ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT)
429 	    & CCM_CBCDR_AHB_PODF_MASK;
430 	return imxccm_get_periphclk(sc) / (ahb_podf + 1);
431 }
432 
433 uint32_t
434 imxccm_get_ipgclk(struct imxccm_softc *sc)
435 {
436 	uint32_t ipg_podf;
437 
438 	ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT)
439 	    & CCM_CBCDR_IPG_PODF_MASK;
440 	return imxccm_get_ahbclk(sc) / (ipg_podf + 1);
441 }
442 
443 uint32_t
444 imxccm_get_ipg_perclk(struct imxccm_softc *sc)
445 {
446 	uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
447 	uint32_t freq, ipg_podf;
448 
449 	if (sc->sc_gates == imx6ul_gates &&
450 	    cscmr1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK)
451 		freq = HCLK_FREQ;
452 	else
453 		freq = imxccm_get_ipgclk(sc);
454 
455 	ipg_podf = cscmr1 & CCM_CSCMR1_PERCLK_CLK_PODF_MASK;
456 
457 	return freq / (ipg_podf + 1);
458 }
459 
460 void
461 imxccm_imx6_enable_pll_enet(struct imxccm_softc *sc, int on)
462 {
463 	KASSERT(on);
464 
465 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
466 	    CCM_ANALOG_PLL_ENET_POWERDOWN);
467 
468 	/* Wait for the PLL to lock. */
469 	while ((regmap_read_4(sc->sc_anatop,
470 	    CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK) == 0)
471 		;
472 
473 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR,
474 	    CCM_ANALOG_PLL_ENET_BYPASS);
475 }
476 
477 void
478 imxccm_imx6_enable_pll_usb1(struct imxccm_softc *sc, int on)
479 {
480 	KASSERT(on);
481 
482 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
483 	    CCM_ANALOG_PLL_USB1_POWER);
484 
485 	/* Wait for the PLL to lock. */
486 	while ((regmap_read_4(sc->sc_anatop,
487 	    CCM_ANALOG_PLL_USB1) & CCM_ANALOG_PLL_USB1_LOCK) == 0)
488 		;
489 
490 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_CLR,
491 	    CCM_ANALOG_PLL_USB1_BYPASS);
492 }
493 
494 void
495 imxccm_imx6_enable_pll_usb2(struct imxccm_softc *sc, int on)
496 {
497 	KASSERT(on);
498 
499 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
500 	    CCM_ANALOG_PLL_USB2_POWER);
501 
502 	/* Wait for the PLL to lock. */
503 	while ((regmap_read_4(sc->sc_anatop,
504 	    CCM_ANALOG_PLL_USB2) & CCM_ANALOG_PLL_USB2_LOCK) == 0)
505 		;
506 
507 	regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_CLR,
508 	    CCM_ANALOG_PLL_USB2_BYPASS);
509 }
510 
511 uint32_t
512 imxccm_imx7d_enet(struct imxccm_softc *sc, uint32_t idx)
513 {
514 	uint32_t mux;
515 
516 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
517 		return 0;
518 
519 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
520 	mux >>= sc->sc_muxs[idx].shift;
521 	mux &= sc->sc_muxs[idx].mask;
522 
523 	switch (mux) {
524 	case 0:
525 		return clock_get_frequency(sc->sc_node, "osc");
526 	case 7:
527 		return 392000000; /* pll_sys_pfd4_clk XXX not fixed */
528 	default:
529 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
530 		return 0;
531 	}
532 }
533 
534 uint32_t
535 imxccm_imx7d_i2c(struct imxccm_softc *sc, uint32_t idx)
536 {
537 	uint32_t mux;
538 
539 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
540 		return 0;
541 
542 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
543 	mux >>= sc->sc_muxs[idx].shift;
544 	mux &= sc->sc_muxs[idx].mask;
545 
546 	switch (mux) {
547 	case 0:
548 		return clock_get_frequency(sc->sc_node, "osc");
549 	case 1:
550 		return 120000000; /* pll_sys_main_120m_clk */
551 	default:
552 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
553 		return 0;
554 	}
555 }
556 
557 uint32_t
558 imxccm_imx7d_uart(struct imxccm_softc *sc, uint32_t idx)
559 {
560 	uint32_t mux;
561 
562 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
563 		return 0;
564 
565 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
566 	mux >>= sc->sc_muxs[idx].shift;
567 	mux &= sc->sc_muxs[idx].mask;
568 
569 	switch (mux) {
570 	case 0:
571 		return clock_get_frequency(sc->sc_node, "osc");
572 	default:
573 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
574 		return 0;
575 	}
576 }
577 
578 uint32_t
579 imxccm_imx7d_usdhc(struct imxccm_softc *sc, uint32_t idx)
580 {
581 	uint32_t mux;
582 
583 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
584 		return 0;
585 
586 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
587 	mux >>= sc->sc_muxs[idx].shift;
588 	mux &= sc->sc_muxs[idx].mask;
589 
590 	switch (mux) {
591 	case 0:
592 		return clock_get_frequency(sc->sc_node, "osc");
593 	case 1:
594 		return 392000000; /* pll_sys_pfd0_392m_clk */
595 	default:
596 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
597 		return 0;
598 	}
599 }
600 
601 uint32_t
602 imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t idx)
603 {
604 	uint32_t mux;
605 
606 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
607 		return 0;
608 
609 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
610 	mux >>= sc->sc_muxs[idx].shift;
611 	mux &= sc->sc_muxs[idx].mask;
612 
613 	switch (mux) {
614 	case 0:
615 		return clock_get_frequency(sc->sc_node, "osc_25m");
616 	case 1:
617 		return 200 * 1000 * 1000; /* sys2_pll_200m */
618 	default:
619 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
620 		return 0;
621 	}
622 }
623 
624 uint32_t
625 imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t idx)
626 {
627 	uint32_t mux;
628 
629 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
630 		return 0;
631 
632 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
633 	mux >>= sc->sc_muxs[idx].shift;
634 	mux &= sc->sc_muxs[idx].mask;
635 
636 	switch (mux) {
637 	case 0:
638 		return clock_get_frequency(sc->sc_node, "osc_25m");
639 	case 1:
640 		return 266 * 1000 * 1000; /* sys1_pll_266m */
641 	default:
642 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
643 		return 0;
644 	}
645 }
646 
647 uint32_t
648 imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t idx)
649 {
650 	uint32_t mux;
651 
652 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
653 		return 0;
654 
655 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
656 	mux >>= sc->sc_muxs[idx].shift;
657 	mux &= sc->sc_muxs[idx].mask;
658 
659 	switch (mux) {
660 	case 0:
661 		return clock_get_frequency(sc->sc_node, "osc_25m");
662 	default:
663 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
664 		return 0;
665 	}
666 }
667 
668 uint32_t
669 imxccm_imx8mq_pwm(struct imxccm_softc *sc, uint32_t idx)
670 {
671 	uint32_t mux;
672 
673 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
674 		return 0;
675 
676 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
677 	mux >>= sc->sc_muxs[idx].shift;
678 	mux &= sc->sc_muxs[idx].mask;
679 
680 	switch (mux) {
681 	case 0:
682 		return clock_get_frequency(sc->sc_node, "osc_25m");
683 	case 1:
684 		return 100 * 1000 * 1000; /* sys1_pll_100m */
685 	case 2:
686 		return 160 * 1000 * 1000; /* sys1_pll_160m */
687 	case 3:
688 		return 40 * 1000 * 1000; /* sys1_pll_40m */
689 	default:
690 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
691 		return 0;
692 	}
693 }
694 
695 uint32_t
696 imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t idx)
697 {
698 	uint32_t mux;
699 
700 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
701 		return 0;
702 
703 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
704 	mux >>= sc->sc_muxs[idx].shift;
705 	mux &= sc->sc_muxs[idx].mask;
706 
707 	switch (mux) {
708 	case 0:
709 		return clock_get_frequency(sc->sc_node, "osc_25m");
710 	default:
711 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
712 		return 0;
713 	}
714 }
715 
716 uint32_t
717 imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t idx)
718 {
719 	uint32_t mux;
720 
721 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
722 		return 0;
723 
724 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
725 	mux >>= sc->sc_muxs[idx].shift;
726 	mux &= sc->sc_muxs[idx].mask;
727 
728 	switch (mux) {
729 	case 0:
730 		return clock_get_frequency(sc->sc_node, "osc_25m");
731 	case 1:
732 		return 400 * 1000 * 1000; /* sys1_pll_400m */
733 	default:
734 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
735 		return 0;
736 	}
737 }
738 
739 uint32_t
740 imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t idx)
741 {
742 	uint32_t mux;
743 
744 	if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0)
745 		return 0;
746 
747 	mux = HREAD4(sc, sc->sc_muxs[idx].reg);
748 	mux >>= sc->sc_muxs[idx].shift;
749 	mux &= sc->sc_muxs[idx].mask;
750 
751 	switch (mux) {
752 	case 0:
753 		return clock_get_frequency(sc->sc_node, "osc_25m");
754 	case 1:
755 		if (idx == IMX8MQ_CLK_USB_CORE_REF ||
756 		    idx == IMX8MQ_CLK_USB_PHY_REF)
757 			return 100 * 1000 * 1000; /* sys1_pll_100m */
758 		if (idx == IMX8MQ_CLK_USB_BUS)
759 			return 500 * 1000 * 1000; /* sys2_pll_500m */
760 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
761 		return 0;
762 	default:
763 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
764 		return 0;
765 	}
766 }
767 
768 uint32_t
769 imxccm_imx8mq_get_pll(struct imxccm_softc *sc, uint32_t idx)
770 {
771 	uint32_t divr_val, divq_val, divf_val;
772 	uint32_t divff, divfi;
773 	uint32_t pllout_div;
774 	uint32_t pll0, pll1;
775 	uint32_t freq;
776 	uint32_t mux;
777 
778 	pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
779 
780 	switch (idx) {
781 	case IMX8MQ_ARM_PLL:
782 		pll0 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL0);
783 		pll1 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL1);
784 		pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
785 		pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
786 		break;
787 	default:
788 		printf("%s: 0x%08x\n", __func__, idx);
789 		return 0;
790 	}
791 
792 	if (pll0 & CCM_FRAC_PLL_POWERDOWN)
793 		return 0;
794 
795 	if ((pll0 & CCM_FRAC_PLL_ENABLE) == 0)
796 		return 0;
797 
798 	mux = (pll0 >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
799 	    CCM_FRAC_PLL_REFCLK_SEL_MASK;
800 	switch (mux) {
801 	case 0:
802 		freq = clock_get_frequency(sc->sc_node, "osc_25m");
803 		break;
804 	case 1:
805 	case 2:
806 		freq = clock_get_frequency(sc->sc_node, "osc_27m");
807 		break;
808 	default:
809 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
810 		return 0;
811 	}
812 
813 	if (pll0 & CCM_FRAC_PLL_BYPASS)
814 		return freq;
815 
816 	divr_val = (pll0 >> CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT) &
817 	    CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK;
818 	divq_val = pll0 & CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
819 	divff = (pll1 >> CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT) &
820 	    CCM_FRAC_PLL_FRAC_DIV_CTL_MASK;
821 	divfi = pll1 & CCM_FRAC_PLL_INT_DIV_CTL_MASK;
822 	divf_val = 1 + divfi + divff / CCM_FRAC_PLL_DENOM;
823 
824 	freq = freq / (divr_val + 1) * 8 * divf_val / ((divq_val + 1) * 2);
825 	return freq / (pllout_div + 1);
826 }
827 
828 int
829 imxccm_imx8mq_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq)
830 {
831 	uint64_t divff, divfi, divr;
832 	uint32_t pllout_div;
833 	uint32_t pll0, pll1;
834 	uint32_t mux, reg;
835 	uint64_t pfreq;
836 	int i;
837 
838 	pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG);
839 
840 	switch (idx) {
841 	case IMX8MQ_ARM_PLL:
842 		pll0 = CCM_FRAC_IMX8M_ARM_PLL0;
843 		pll1 = CCM_FRAC_IMX8M_ARM_PLL1;
844 		pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT;
845 		pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK;
846 		/* XXX: Assume fixed divider to ease math. */
847 		KASSERT(pllout_div == 0);
848 		divr = 5;
849 		break;
850 	default:
851 		printf("%s: 0x%08x\n", __func__, idx);
852 		return -1;
853 	}
854 
855 	reg = regmap_read_4(sc->sc_anatop, pll0);
856 	mux = (reg >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) &
857 	    CCM_FRAC_PLL_REFCLK_SEL_MASK;
858 	switch (mux) {
859 	case 0:
860 		pfreq = clock_get_frequency(sc->sc_node, "osc_25m");
861 		break;
862 	case 1:
863 	case 2:
864 		pfreq = clock_get_frequency(sc->sc_node, "osc_27m");
865 		break;
866 	default:
867 		printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux);
868 		return -1;
869 	}
870 
871 	/* Frac divider follows the PLL */
872 	freq *= divr;
873 
874 	/* PLL calculation */
875 	freq *= 2;
876 	pfreq *= 8;
877 	divfi = freq / pfreq;
878 	divff = (uint64_t)(freq - divfi * pfreq);
879 	divff = (divff * CCM_FRAC_PLL_DENOM) / pfreq;
880 
881 	reg = regmap_read_4(sc->sc_anatop, pll1);
882 	reg &= ~(CCM_FRAC_PLL_FRAC_DIV_CTL_MASK << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT);
883 	reg |= divff << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT;
884 	reg &= ~(CCM_FRAC_PLL_INT_DIV_CTL_MASK << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT);
885 	reg |= (divfi - 1) << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT;
886 	regmap_write_4(sc->sc_anatop, pll1, reg);
887 
888 	reg = regmap_read_4(sc->sc_anatop, pll0);
889 	reg &= ~CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK;
890 	reg &= ~(CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT);
891 	reg |= (divr - 1) << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT;
892 	regmap_write_4(sc->sc_anatop, pll0, reg);
893 
894 	reg = regmap_read_4(sc->sc_anatop, pll0);
895 	reg |= CCM_FRAC_PLL_NEWDIV_VAL;
896 	regmap_write_4(sc->sc_anatop, pll0, reg);
897 
898 	for (i = 0; i < 5000; i++) {
899 		reg = regmap_read_4(sc->sc_anatop, pll0);
900 		if (reg & CCM_FRAC_PLL_BYPASS)
901 			break;
902 		if (reg & CCM_FRAC_PLL_POWERDOWN)
903 			break;
904 		if (reg & CCM_FRAC_PLL_NEWDIV_ACK)
905 			break;
906 		delay(10);
907 	}
908 	if (i == 5000)
909 		printf("%s: timeout\n", __func__);
910 
911 	reg = regmap_read_4(sc->sc_anatop, pll0);
912 	reg &= ~CCM_FRAC_PLL_NEWDIV_VAL;
913 	regmap_write_4(sc->sc_anatop, pll0, reg);
914 
915 	return 0;
916 }
917 
918 void
919 imxccm_enable_parent(struct imxccm_softc *sc, uint32_t parent, int on)
920 {
921 	if (on)
922 		imxccm_enable(sc, &parent, on);
923 }
924 
925 void
926 imxccm_enable(void *cookie, uint32_t *cells, int on)
927 {
928 	struct imxccm_softc *sc = cookie;
929 	uint32_t idx = cells[0], parent;
930 	uint16_t reg;
931 	uint8_t pos;
932 
933 	/* Dummy clock. */
934 	if (idx == 0)
935 		return;
936 
937 	if (sc->sc_gates == imx7d_gates) {
938 		if (sc->sc_anatop == NULL) {
939 			sc->sc_anatop = regmap_bycompatible("fsl,imx7d-anatop");
940 			KASSERT(sc->sc_anatop);
941 		}
942 
943 		switch (idx) {
944 		case IMX7D_PLL_ENET_MAIN_125M_CLK:
945 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_SET,
946 			    CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ);
947 			return;
948 		default:
949 			break;
950 		}
951 	} else if (sc->sc_gates == imx6_gates) {
952 		if (sc->sc_anatop == NULL) {
953 			sc->sc_anatop = regmap_bycompatible("fsl,imx6q-anatop");
954 			KASSERT(sc->sc_anatop);
955 		}
956 
957 		switch (idx) {
958 		case IMX6_CLK_PLL3:
959 			imxccm_imx6_enable_pll_usb1(sc, on);
960 			return;
961 		case IMX6_CLK_PLL6:
962 			imxccm_imx6_enable_pll_enet(sc, on);
963 			return;
964 		case IMX6_CLK_PLL7:
965 			imxccm_imx6_enable_pll_usb2(sc, on);
966 			return;
967 		case IMX6_CLK_PLL3_USB_OTG:
968 			imxccm_enable_parent(sc, IMX6_CLK_PLL3, on);
969 			regmap_write_4(sc->sc_anatop,
970 			    on ? CCM_ANALOG_PLL_USB1_SET : CCM_ANALOG_PLL_USB1_CLR,
971 			    CCM_ANALOG_PLL_USB1_ENABLE);
972 			return;
973 		case IMX6_CLK_PLL6_ENET:
974 			imxccm_enable_parent(sc, IMX6_CLK_PLL6, on);
975 			regmap_write_4(sc->sc_anatop,
976 			    on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
977 			    CCM_ANALOG_PLL_ENET_ENABLE);
978 			return;
979 		case IMX6_CLK_PLL7_USB_HOST:
980 			imxccm_enable_parent(sc, IMX6_CLK_PLL7, on);
981 			regmap_write_4(sc->sc_anatop,
982 			    on ? CCM_ANALOG_PLL_USB2_SET : CCM_ANALOG_PLL_USB2_CLR,
983 			    CCM_ANALOG_PLL_USB2_ENABLE);
984 			return;
985 		case IMX6_CLK_USBPHY1:
986 			/* PLL outputs should alwas be on. */
987 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET,
988 			    CCM_ANALOG_PLL_USB1_EN_USB_CLKS);
989 			imxccm_enable_parent(sc, IMX6_CLK_PLL3_USB_OTG, on);
990 			return;
991 		case IMX6_CLK_USBPHY2:
992 			/* PLL outputs should alwas be on. */
993 			regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET,
994 			    CCM_ANALOG_PLL_USB2_EN_USB_CLKS);
995 			imxccm_enable_parent(sc, IMX6_CLK_PLL7_USB_HOST, on);
996 			return;
997 		case IMX6_CLK_SATA_REF_100:
998 			imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
999 			regmap_write_4(sc->sc_anatop,
1000 			   on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR,
1001 			   CCM_ANALOG_PLL_ENET_ENABLE_100M);
1002 			return;
1003 		case IMX6_CLK_ENET_REF:
1004 			imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on);
1005 			return;
1006 		case IMX6_CLK_IPG:
1007 		case IMX6_CLK_IPG_PER:
1008 		case IMX6_CLK_ECSPI_ROOT:
1009 			/* always on */
1010 			return;
1011 		default:
1012 			break;
1013 		}
1014 	}
1015 
1016 	if (on) {
1017 		if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
1018 			parent = sc->sc_gates[idx].parent;
1019 			imxccm_enable(sc, &parent, on);
1020 		}
1021 
1022 		if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
1023 			parent = sc->sc_divs[idx].parent;
1024 			imxccm_enable(sc, &parent, on);
1025 		}
1026 	}
1027 
1028 	if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) {
1029 		if ((idx < sc->sc_ndivs && sc->sc_divs[idx].reg != 0) ||
1030 		    (idx < sc->sc_nmuxs && sc->sc_muxs[idx].reg != 0))
1031 			return;
1032 		printf("%s: 0x%08x\n", __func__, idx);
1033 		return;
1034 	}
1035 
1036 	reg = sc->sc_gates[idx].reg;
1037 	pos = sc->sc_gates[idx].pos;
1038 
1039 	if (on)
1040 		HSET4(sc, reg, 0x3 << (2 * pos));
1041 	else
1042 		HCLR4(sc, reg, 0x3 << (2 * pos));
1043 }
1044 
1045 uint32_t
1046 imxccm_get_frequency(void *cookie, uint32_t *cells)
1047 {
1048 	struct imxccm_softc *sc = cookie;
1049 	uint32_t idx = cells[0];
1050 	uint32_t div, pre, reg, parent;
1051 	uint32_t freq;
1052 
1053 	/* Dummy clock. */
1054 	if (idx == 0)
1055 		return 0;
1056 
1057 	if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) {
1058 		parent = sc->sc_gates[idx].parent;
1059 		return imxccm_get_frequency(sc, &parent);
1060 	}
1061 
1062 	if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) {
1063 		div = HREAD4(sc, sc->sc_divs[idx].reg);
1064 		div = div >> sc->sc_divs[idx].shift;
1065 		div = div & sc->sc_divs[idx].mask;
1066 		parent = sc->sc_divs[idx].parent;
1067 		return imxccm_get_frequency(sc, &parent) / (div + 1);
1068 	}
1069 
1070 	if (sc->sc_gates == imx8mq_gates) {
1071 		switch (idx) {
1072 		case IMX8MQ_CLK_ARM:
1073 			parent = IMX8MQ_ARM_PLL;
1074 			return imxccm_get_frequency(sc, &parent);
1075 		case IMX8MQ_ARM_PLL:
1076 			return imxccm_imx8mq_get_pll(sc, idx);
1077 		}
1078 
1079 		/* These are composite clocks. */
1080 		if (idx < sc->sc_ngates && sc->sc_gates[idx].reg &&
1081 		    idx < sc->sc_ndivs && sc->sc_divs[idx].reg &&
1082 		    idx < sc->sc_npredivs && sc->sc_predivs[idx].reg) {
1083 			switch (idx) {
1084 			case IMX8MQ_CLK_ENET_AXI:
1085 				freq = imxccm_imx8mq_enet(sc, idx);
1086 				break;
1087 			case IMX8MQ_CLK_I2C1:
1088 			case IMX8MQ_CLK_I2C2:
1089 			case IMX8MQ_CLK_I2C3:
1090 			case IMX8MQ_CLK_I2C4:
1091 				freq = imxccm_imx8mq_i2c(sc, idx);
1092 				break;
1093 			case IMX8MQ_CLK_UART1:
1094 			case IMX8MQ_CLK_UART2:
1095 			case IMX8MQ_CLK_UART3:
1096 			case IMX8MQ_CLK_UART4:
1097 				freq = imxccm_imx8mq_uart(sc, idx);
1098 				break;
1099 			case IMX8MQ_CLK_USDHC1:
1100 			case IMX8MQ_CLK_USDHC2:
1101 				freq = imxccm_imx8mq_usdhc(sc, idx);
1102 				break;
1103 			case IMX8MQ_CLK_USB_BUS:
1104 			case IMX8MQ_CLK_USB_CORE_REF:
1105 			case IMX8MQ_CLK_USB_PHY_REF:
1106 				freq = imxccm_imx8mq_usb(sc, idx);
1107 				break;
1108 			case IMX8MQ_CLK_ECSPI1:
1109 			case IMX8MQ_CLK_ECSPI2:
1110 			case IMX8MQ_CLK_ECSPI3:
1111 				freq = imxccm_imx8mq_ecspi(sc, idx);
1112 				break;
1113 			case IMX8MQ_CLK_PWM1:
1114 			case IMX8MQ_CLK_PWM2:
1115 			case IMX8MQ_CLK_PWM3:
1116 			case IMX8MQ_CLK_PWM4:
1117 				freq = imxccm_imx8mq_pwm(sc, idx);
1118 				break;
1119 			default:
1120 				printf("%s: 0x%08x\n", __func__, idx);
1121 				return 0;
1122 			}
1123 
1124 			reg = HREAD4(sc, sc->sc_divs[idx].reg);
1125 			div = reg >> sc->sc_divs[idx].shift;
1126 			div = div & sc->sc_divs[idx].mask;
1127 			pre = reg >> sc->sc_predivs[idx].shift;
1128 			pre = pre & sc->sc_predivs[idx].mask;
1129 			return ((freq / (pre + 1)) / (div + 1));
1130 		}
1131 
1132 	} else if (sc->sc_gates == imx7d_gates) {
1133 		switch (idx) {
1134 		case IMX7D_ENET_AXI_ROOT_SRC:
1135 			return imxccm_imx7d_enet(sc, idx);
1136 		case IMX7D_I2C1_ROOT_SRC:
1137 		case IMX7D_I2C2_ROOT_SRC:
1138 		case IMX7D_I2C3_ROOT_SRC:
1139 		case IMX7D_I2C4_ROOT_SRC:
1140 			return imxccm_imx7d_i2c(sc, idx);
1141 		case IMX7D_UART1_ROOT_SRC:
1142 		case IMX7D_UART2_ROOT_SRC:
1143 		case IMX7D_UART3_ROOT_SRC:
1144 		case IMX7D_UART4_ROOT_SRC:
1145 		case IMX7D_UART5_ROOT_SRC:
1146 		case IMX7D_UART6_ROOT_SRC:
1147 		case IMX7D_UART7_ROOT_SRC:
1148 			return imxccm_imx7d_uart(sc, idx);
1149 		case IMX7D_USDHC1_ROOT_SRC:
1150 		case IMX7D_USDHC2_ROOT_SRC:
1151 		case IMX7D_USDHC3_ROOT_SRC:
1152 			return imxccm_imx7d_usdhc(sc, idx);
1153 		}
1154 	} else if (sc->sc_gates == imx6ul_gates) {
1155 		switch (idx) {
1156 		case IMX6UL_CLK_ARM:
1157 			return imxccm_get_armclk(sc);
1158 		case IMX6UL_CLK_IPG:
1159 			return imxccm_get_ipgclk(sc);
1160 		case IMX6UL_CLK_PERCLK:
1161 			return imxccm_get_ipg_perclk(sc);
1162 		case IMX6UL_CLK_UART1_SERIAL:
1163 			return imxccm_get_uartclk(sc);
1164 		case IMX6UL_CLK_USDHC1:
1165 		case IMX6UL_CLK_USDHC2:
1166 			return imxccm_get_usdhx(sc, idx - IMX6UL_CLK_USDHC1 + 1);
1167 		}
1168 	} else if (sc->sc_gates == imx6_gates) {
1169 		switch (idx) {
1170 		case IMX6_CLK_AHB:
1171 			return imxccm_get_ahbclk(sc);
1172 		case IMX6_CLK_ARM:
1173 			return imxccm_get_armclk(sc);
1174 		case IMX6_CLK_IPG:
1175 			return imxccm_get_ipgclk(sc);
1176 		case IMX6_CLK_IPG_PER:
1177 			return imxccm_get_ipg_perclk(sc);
1178 		case IMX6_CLK_ECSPI_ROOT:
1179 			return imxccm_get_ecspiclk(sc);
1180 		case IMX6_CLK_UART_SERIAL:
1181 			return imxccm_get_uartclk(sc);
1182 		case IMX6_CLK_USDHC1:
1183 		case IMX6_CLK_USDHC2:
1184 		case IMX6_CLK_USDHC3:
1185 		case IMX6_CLK_USDHC4:
1186 			return imxccm_get_usdhx(sc, idx - IMX6_CLK_USDHC1 + 1);
1187 		}
1188 	}
1189 
1190 	printf("%s: 0x%08x\n", __func__, idx);
1191 	return 0;
1192 }
1193 
1194 int
1195 imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
1196 {
1197 	struct imxccm_softc *sc = cookie;
1198 	uint32_t idx = cells[0];
1199 	uint32_t reg, div, parent, parent_freq;
1200 	uint32_t pcells[2];
1201 	int ret;
1202 
1203 	if (sc->sc_divs == imx8mq_divs) {
1204 		switch (idx) {
1205 		case IMX8MQ_CLK_ARM:
1206 			parent = IMX8MQ_CLK_A53_SRC;
1207 			return imxccm_set_frequency(cookie, &parent, freq);
1208 		case IMX8MQ_CLK_A53_SRC:
1209 			pcells[0] = sc->sc_phandle;
1210 			pcells[1] = IMX8MQ_SYS1_PLL_800M;
1211 			ret = imxccm_set_parent(cookie, &idx, pcells);
1212 			if (ret)
1213 				return ret;
1214 			ret = imxccm_imx8mq_set_pll(sc, IMX8MQ_ARM_PLL, freq);
1215 			pcells[0] = sc->sc_phandle;
1216 			pcells[1] = IMX8MQ_ARM_PLL_OUT;
1217 			imxccm_set_parent(cookie, &idx, pcells);
1218 			return ret;
1219 		case IMX8MQ_CLK_USB_BUS:
1220 		case IMX8MQ_CLK_USB_CORE_REF:
1221 		case IMX8MQ_CLK_USB_PHY_REF:
1222 			if (imxccm_get_frequency(sc, cells) != freq)
1223 				break;
1224 			return 0;
1225 		case IMX8MQ_CLK_USDHC1:
1226 			imxccm_enable(cookie, &idx, 1);
1227 			reg = HREAD4(sc, sc->sc_divs[idx].reg);
1228 			reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
1229 			HWRITE4(sc, sc->sc_divs[idx].reg, reg);
1230 			reg = HREAD4(sc, sc->sc_predivs[idx].reg);
1231 			reg &= ~(sc->sc_predivs[idx].mask << sc->sc_predivs[idx].shift);
1232 			HWRITE4(sc, sc->sc_predivs[idx].reg, reg);
1233 			return 0;
1234 		}
1235 	} else if (sc->sc_divs == imx7d_divs) {
1236 		switch (idx) {
1237 		case IMX7D_USDHC1_ROOT_CLK:
1238 		case IMX7D_USDHC2_ROOT_CLK:
1239 		case IMX7D_USDHC3_ROOT_CLK:
1240 			parent = sc->sc_gates[idx].parent;
1241 			return imxccm_set_frequency(sc, &parent, freq);
1242 		case IMX7D_USDHC1_ROOT_DIV:
1243 		case IMX7D_USDHC2_ROOT_DIV:
1244 		case IMX7D_USDHC3_ROOT_DIV:
1245 			parent = sc->sc_divs[idx].parent;
1246 			parent_freq = imxccm_get_frequency(sc, &parent);
1247 			div = 0;
1248 			while (parent_freq / (div + 1) > freq)
1249 				div++;
1250 			reg = HREAD4(sc, sc->sc_divs[idx].reg);
1251 			reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift);
1252 			reg |= (div << sc->sc_divs[idx].shift);
1253 			HWRITE4(sc, sc->sc_divs[idx].reg, reg);
1254 			return 0;
1255 		}
1256 	}
1257 
1258 	printf("%s: 0x%08x %x\n", __func__, idx, freq);
1259 	return -1;
1260 }
1261 
1262 int
1263 imxccm_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells)
1264 {
1265 	struct imxccm_softc *sc = cookie;
1266 	uint32_t idx = cells[0];
1267 	uint32_t pidx;
1268 	uint32_t mux;
1269 
1270 	if (pcells[0] != sc->sc_phandle) {
1271 		printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, pcells[0]);
1272 		return -1;
1273 	}
1274 
1275 	pidx = pcells[1];
1276 
1277 	if (sc->sc_muxs == imx8mq_muxs) {
1278 		switch (idx) {
1279 		case IMX8MQ_CLK_A53_SRC:
1280 			if (pidx != IMX8MQ_ARM_PLL_OUT &&
1281 			    pidx != IMX8MQ_SYS1_PLL_800M)
1282 				break;
1283 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1284 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1285 			if (pidx == IMX8MQ_ARM_PLL_OUT)
1286 				mux |= (0x1 << sc->sc_muxs[idx].shift);
1287 			if (pidx == IMX8MQ_SYS1_PLL_800M)
1288 				mux |= (0x4 << sc->sc_muxs[idx].shift);
1289 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1290 			return 0;
1291 		case IMX8MQ_CLK_USB_BUS:
1292 			if (pidx != IMX8MQ_SYS2_PLL_500M)
1293 				break;
1294 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1295 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1296 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1297 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1298 			return 0;
1299 		case IMX8MQ_CLK_USB_CORE_REF:
1300 		case IMX8MQ_CLK_USB_PHY_REF:
1301 			if (pidx != IMX8MQ_SYS1_PLL_100M)
1302 				break;
1303 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1304 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1305 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1306 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1307 			return 0;
1308 		case IMX8MQ_CLK_PCIE1_CTRL:
1309 		case IMX8MQ_CLK_PCIE2_CTRL:
1310 			if (pidx != IMX8MQ_SYS2_PLL_250M)
1311 				break;
1312 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1313 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1314 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1315 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1316 			return 0;
1317 		case IMX8MQ_CLK_PCIE1_PHY:
1318 		case IMX8MQ_CLK_PCIE2_PHY:
1319 			if (pidx != IMX8MQ_SYS2_PLL_100M)
1320 				break;
1321 			mux = HREAD4(sc, sc->sc_muxs[idx].reg);
1322 			mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift);
1323 			mux |= (0x1 << sc->sc_muxs[idx].shift);
1324 			HWRITE4(sc, sc->sc_muxs[idx].reg, mux);
1325 			return 0;
1326 		}
1327 	}
1328 
1329 	printf("%s: 0x%08x 0x%08x\n", __func__, idx, pidx);
1330 	return -1;
1331 }
1332