xref: /netbsd-src/sys/arch/arm/imx/imx51_ccm.c (revision 7991f5a7b8fc83a3d55dc2a1767cca3b84103969)
1 /*	$NetBSD: imx51_ccm.c,v 1.8 2021/07/24 21:31:32 andvar Exp $	*/
2 
3 /*
4  * Copyright (c) 2010-2012, 2014  Genetec Corporation.  All rights reserved.
5  * Written by Hashimoto Kenichi for Genetec Corporation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Clock Controller Module (CCM) for i.MX5
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: imx51_ccm.c,v 1.8 2021/07/24 21:31:32 andvar Exp $");
35 
36 #include "opt_imx.h"
37 #include "opt_imx51clk.h"
38 
39 #include "locators.h"
40 
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <sys/bus.h>
44 #include <sys/device.h>
45 #include <sys/param.h>
46 
47 #include <machine/cpu.h>
48 
49 #include <arm/imx/imx51_ccmvar.h>
50 #include <arm/imx/imx51_ccmreg.h>
51 #include <arm/imx/imx51_dpllreg.h>
52 
53 #include <arm/imx/imx51var.h>
54 #include <arm/imx/imx51reg.h>
55 
56 #ifndef	IMX51_OSC_FREQ
57 #define	IMX51_OSC_FREQ	(24 * 1000 * 1000)	/* 24MHz */
58 #endif
59 
60 struct imxccm_softc {
61 	device_t	sc_dev;
62 	bus_space_tag_t	sc_iot;
63 	bus_space_handle_t	sc_ioh;
64 
65 	struct {
66 		bus_space_handle_t pll_ioh;
67 		u_int pll_freq;
68 	} sc_pll[IMX51_N_DPLLS];
69 };
70 
71 struct imxccm_softc *ccm_softc;
72 
73 static uint64_t imx51_get_pll_freq(u_int);
74 #if IMX50
75 static uint64_t imx51_get_pfd_freq(u_int);
76 #endif
77 
78 static int imxccm_match(device_t, cfdata_t, void *);
79 static void imxccm_attach(device_t, device_t, void *);
80 
81 CFATTACH_DECL_NEW(imxccm, sizeof(struct imxccm_softc),
82     imxccm_match, imxccm_attach, NULL, NULL);
83 
84 static int
imxccm_match(device_t parent,cfdata_t cfdata,void * aux)85 imxccm_match(device_t parent, cfdata_t cfdata, void *aux)
86 {
87 	struct axi_attach_args *aa = aux;
88 
89 	if (ccm_softc != NULL)
90 		return 0;
91 
92 	if (aa->aa_addr == CCMC_BASE)
93 		return 1;
94 
95 	return 0;
96 }
97 
98 static void
imxccm_attach(device_t parent,device_t self,void * aux)99 imxccm_attach(device_t parent, device_t self, void *aux)
100 {
101 	struct imxccm_softc * const sc = device_private(self);
102 	struct axi_attach_args *aa = aux;
103 	bus_space_tag_t iot = aa->aa_iot;
104 
105 	ccm_softc = sc;
106 	sc->sc_dev = self;
107 	sc->sc_iot = iot;
108 
109 	if (bus_space_map(iot, aa->aa_addr, CCMC_SIZE, 0, &sc->sc_ioh)) {
110 		aprint_error(": can't map registers\n");
111 		return;
112 	}
113 
114 	for (u_int i=1; i <= IMX51_N_DPLLS; ++i) {
115 		if (bus_space_map(iot, DPLL_BASE(i), DPLL_SIZE, 0,
116 			&sc->sc_pll[i-1].pll_ioh)) {
117 			aprint_error(": can't map pll registers\n");
118 			return;
119 		}
120 	}
121 
122 	aprint_normal(": Clock control module\n");
123 	aprint_naive("\n");
124 
125 	imx51_get_pll_freq(1);
126 	imx51_get_pll_freq(2);
127 	imx51_get_pll_freq(3);
128 
129 	aprint_verbose_dev(self, "CPU clock=%d, UART clock=%d\n",
130 	    imx51_get_clock(IMX51CLK_ARM_ROOT),
131 	    imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
132 	aprint_verbose_dev(self, "PLL1 clock=%d, PLL2 clock=%d, PLL3 clock=%d\n",
133 	    imx51_get_clock(IMX51CLK_PLL1),
134 	    imx51_get_clock(IMX51CLK_PLL2),
135 	    imx51_get_clock(IMX51CLK_PLL3));
136 	aprint_verbose_dev(self,
137 	    "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
138 	    imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
139 	    imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
140 	    imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
141 	    imx51_get_clock(IMX51CLK_PERCLK_ROOT));
142 	aprint_verbose_dev(self, "ESDHC1 clock=%d\n",
143 	    imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
144 }
145 
146 
147 u_int
imx51_get_clock(enum imx51_clock clk)148 imx51_get_clock(enum imx51_clock clk)
149 {
150 	bus_space_tag_t iot = ccm_softc->sc_iot;
151 	bus_space_handle_t ioh = ccm_softc->sc_ioh;
152 
153 	u_int freq = 0;
154 	u_int sel;
155 	uint32_t cacrr;	/* ARM clock root register */
156 	uint32_t ccsr;
157 	uint32_t cscdr1;
158 	uint32_t cscdr2;
159 	uint32_t cscmr1;
160 	uint32_t cbcdr;
161 	uint32_t cbcmr;
162 	uint32_t cdcr;
163 
164 	switch (clk) {
165 	case IMX51CLK_PLL1:
166 	case IMX51CLK_PLL2:
167 	case IMX51CLK_PLL3:
168 		return ccm_softc->sc_pll[clk - IMX51CLK_PLL1].pll_freq;
169 	case IMX51CLK_PLL1SW:
170 		ccsr = bus_space_read_4(iot, ioh, CCMC_CCSR);
171 		if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
172 			return ccm_softc->sc_pll[1-1].pll_freq;
173 		/* step clock */
174 		/* FALLTHROUGH */
175 	case IMX51CLK_PLL1STEP:
176 		ccsr = bus_space_read_4(iot, ioh, CCMC_CCSR);
177 		switch (__SHIFTOUT(ccsr, CCSR_STEP_SEL)) {
178 		case 0:
179 			return imx51_get_clock(IMX51CLK_LP_APM);
180 		case 1:
181 			return 0; /* XXX PLL bypass clock */
182 		case 2:
183 			return ccm_softc->sc_pll[2-1].pll_freq /
184 			    (1 + __SHIFTOUT(ccsr, CCSR_PLL2_DIV_PODF));
185 		case 3:
186 			return ccm_softc->sc_pll[3-1].pll_freq /
187 			    (1 + __SHIFTOUT(ccsr, CCSR_PLL3_DIV_PODF));
188 		}
189 		/*NOTREACHED*/
190 	case IMX51CLK_PLL2SW:
191 		ccsr = bus_space_read_4(iot, ioh, CCMC_CCSR);
192 		if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
193 			return imx51_get_clock(IMX51CLK_PLL2);
194 		return 0; /* XXX PLL2 bypass clk */
195 	case IMX51CLK_PLL3SW:
196 		ccsr = bus_space_read_4(iot, ioh, CCMC_CCSR);
197 		if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
198 			return imx51_get_clock(IMX51CLK_PLL3);
199 		return 0; /* XXX PLL3 bypass clk */
200 
201 	case IMX51CLK_LP_APM:
202 		ccsr = bus_space_read_4(iot, ioh, CCMC_CCSR);
203 		return (ccsr & CCSR_LP_APM) ?
204 			    imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
205 
206 	case IMX51CLK_ARM_ROOT:
207 		freq = imx51_get_clock(IMX51CLK_PLL1SW);
208 		cacrr = bus_space_read_4(iot, ioh, CCMC_CACRR);
209 		return freq / (cacrr + 1);
210 
211 		/* ... */
212 	case IMX51CLK_MAIN_BUS_CLK_SRC:
213 		cbcdr = bus_space_read_4(iot, ioh, CCMC_CBCDR);
214 #if IMX50
215 		switch (__SHIFTOUT(cbcdr, CBCDR_PERIPH_CLK_SEL)) {
216 		case 0:
217 			freq = imx51_get_clock(IMX51CLK_PLL1SW);
218 			break;
219 		case 1:
220 			freq = imx51_get_clock(IMX51CLK_PLL2SW);
221 			break;
222 		case 2:
223 			freq = imx51_get_clock(IMX51CLK_PLL3SW);
224 			break;
225 		case 3:
226 			freq = imx51_get_clock(IMX51CLK_LP_APM);
227 			break;
228 		}
229 #else
230 		if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
231 			freq = imx51_get_clock(IMX51CLK_PLL2SW);
232 		else {
233 			cbcmr = bus_space_read_4(iot, ioh,  CCMC_CBCMR);
234 			switch (__SHIFTOUT(cbcmr, CBCMR_PERIPH_APM_SEL)) {
235 			case 0:
236 				freq = imx51_get_clock(IMX51CLK_PLL1SW);
237 				break;
238 			case 1:
239 				freq = imx51_get_clock(IMX51CLK_PLL3SW);
240 				break;
241 			case 2:
242 				freq = imx51_get_clock(IMX51CLK_LP_APM);
243 				break;
244 			case 3:
245 				/* XXX: error */
246 				break;
247 			}
248 		}
249 #endif
250 		return freq;
251 	case IMX51CLK_MAIN_BUS_CLK:
252 		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
253 		cdcr = bus_space_read_4(iot, ioh, CCMC_CDCR);
254 		if (cdcr & CDCR_SW_PERIPH_CLK_DIV_REQ)
255 			return freq / (1 + __SHIFTOUT(cdcr, CDCR_PERIPH_CLK_DVFS_PODF));
256 		else
257 			return freq;
258 	case IMX51CLK_AHB_CLK_ROOT:
259 		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
260 		cbcdr = bus_space_read_4(iot, ioh, CCMC_CBCDR);
261 		return freq / (1 + __SHIFTOUT(cbcdr, CBCDR_AHB_PODF));
262 	case IMX51CLK_IPG_CLK_ROOT:
263 		freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
264 		cbcdr = bus_space_read_4(iot, ioh, CCMC_CBCDR);
265 		return freq / (1 + __SHIFTOUT(cbcdr, CBCDR_IPG_PODF));
266 	case IMX51CLK_PERCLK_ROOT:
267 		cbcmr = bus_space_read_4(iot, ioh, CCMC_CBCMR);
268 		if (cbcmr & CBCMR_PERCLK_IPG_SEL)
269 			return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
270 		if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
271 			freq = imx51_get_clock(IMX51CLK_LP_APM);
272 		else {
273 #ifdef IMX50
274 			freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
275 #else
276 			freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
277 #endif
278 		}
279 
280 		cbcdr = bus_space_read_4(iot, ioh, CCMC_CBCDR);
281 
282 #ifdef IMXCCMDEBUG
283 		printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
284 #endif
285 
286 		freq /= 1 + __SHIFTOUT(cbcdr, CBCDR_PERCLK_PRED1);
287 		freq /= 1 + __SHIFTOUT(cbcdr, CBCDR_PERCLK_PRED2);
288 		freq /= 1 + __SHIFTOUT(cbcdr, CBCDR_PERCLK_PODF);
289 		return freq;
290 	case IMX51CLK_UART_CLK_ROOT:
291 		cscdr1 = bus_space_read_4(iot, ioh, CCMC_CSCDR1);
292 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
293 
294 #ifdef IMXCCMDEBUG
295 		printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
296 #endif
297 
298 		sel = __SHIFTOUT(cscmr1, CSCMR1_UART_CLK_SEL);
299 
300 		switch (sel) {
301 		case 0:
302 		case 1:
303 		case 2:
304 			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
305 			break;
306 		case 3:
307 			freq = imx51_get_clock(IMX51CLK_LP_APM);
308 			break;
309 		}
310 
311 		return freq / (1 + __SHIFTOUT(cscdr1, CSCDR1_UART_CLK_PRED)) /
312 		    (1 + __SHIFTOUT(cscdr1, CSCDR1_UART_CLK_PODF));
313 	case IMX51CLK_IPU_HSP_CLK_ROOT:
314 		cbcmr = bus_space_read_4(iot, ioh,  CCMC_CBCMR);
315 		switch (__SHIFTOUT(cbcmr, CBCMR_IPU_HSP_CLK_SEL)) {
316 			case 0:
317 				freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
318 				break;
319 			case 1:
320 				freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
321 				break;
322 			case 2:
323 				freq = imx51_get_clock(
324 					IMX51CLK_EMI_SLOW_CLK_ROOT);
325 				break;
326 			case 3:
327 				freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
328 				break;
329 			}
330 		return freq;
331 #ifdef IMX50
332 	case IMX51CLK_ESDHC2_CLK_ROOT:
333 	case IMX51CLK_ESDHC4_CLK_ROOT:
334 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
335 
336 		sel = 0;
337 		if (clk == IMX51CLK_ESDHC2_CLK_ROOT)
338 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC2_CLK_SEL);
339 		else if (clk == IMX51CLK_ESDHC4_CLK_ROOT)
340 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC4_CLK_SEL);
341 
342 		if (sel == 0)
343 			freq = imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT);
344 		else
345 			freq = imx51_get_clock(IMX51CLK_ESDHC3_CLK_ROOT);
346 
347 		return freq;
348 	case IMX51CLK_ESDHC1_CLK_ROOT:
349 	case IMX51CLK_ESDHC3_CLK_ROOT:
350 
351 		cscdr1 = bus_space_read_4(iot, ioh, CCMC_CSCDR1);
352 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
353 
354 		sel = 0;
355 		if (clk == IMX51CLK_ESDHC1_CLK_ROOT)
356 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC1_CLK_SEL);
357 		else if (clk == IMX51CLK_ESDHC3_CLK_ROOT)
358 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC3_CLK_SEL);
359 
360 		switch (sel) {
361 		case 0:
362 		case 1:
363 		case 2:
364 			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
365 			break;
366 		case 3:
367 			freq = imx51_get_clock(IMX51CLK_LP_APM);
368 			break;
369 		case 4:
370 			/* PFD0 XXX */
371 			break;
372 		case 5:
373 			/* PFD1 XXX */
374 			break;
375 		case 6:
376 			/* PFD4 XXX */
377 			break;
378 		case 7:
379 			/* osc_clk XXX */
380 			break;
381 		}
382 
383 		if (clk == IMX51CLK_ESDHC1_CLK_ROOT)
384 			freq = freq / (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC1_CLK_PRED)) /
385 			    (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC1_CLK_PODF));
386 		else if (clk == IMX51CLK_ESDHC3_CLK_ROOT)
387 			freq = freq / (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC3_CLK_PRED)) /
388 			    (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC3_CLK_PODF));
389 		return freq;
390 #else
391 	case IMX51CLK_ESDHC3_CLK_ROOT:
392 	case IMX51CLK_ESDHC4_CLK_ROOT:
393 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
394 
395 		sel = 0;
396 		if (clk == IMX51CLK_ESDHC3_CLK_ROOT)
397 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC3_CLK_SEL);
398 		else if (clk == IMX51CLK_ESDHC4_CLK_ROOT)
399 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC4_CLK_SEL);
400 
401 		if (sel == 0)
402 			freq = imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT);
403 		else
404 			freq = imx51_get_clock(IMX51CLK_ESDHC2_CLK_ROOT);
405 
406 		return freq;
407 	case IMX51CLK_ESDHC1_CLK_ROOT:
408 	case IMX51CLK_ESDHC2_CLK_ROOT:
409 
410 		cscdr1 = bus_space_read_4(iot, ioh, CCMC_CSCDR1);
411 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
412 
413 		sel = 0;
414 		if (clk == IMX51CLK_ESDHC1_CLK_ROOT)
415 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC1_CLK_SEL);
416 		else if (clk == IMX51CLK_ESDHC2_CLK_ROOT)
417 			sel = __SHIFTOUT(cscmr1, CSCMR1_ESDHC2_CLK_SEL);
418 
419 		switch (sel) {
420 		case 0:
421 		case 1:
422 		case 2:
423 			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
424 			break;
425 		case 3:
426 			freq = imx51_get_clock(IMX51CLK_LP_APM);
427 			break;
428 		}
429 
430 		if (clk == IMX51CLK_ESDHC1_CLK_ROOT)
431 			freq = freq / (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC1_CLK_PRED)) /
432 			    (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC1_CLK_PODF));
433 		else if (clk == IMX51CLK_ESDHC2_CLK_ROOT)
434 			freq = freq / (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC2_CLK_PRED)) /
435 			    (1 + __SHIFTOUT(cscdr1, CSCDR1_ESDHC2_CLK_PODF));
436 		return freq;
437 #endif
438 	case IMX51CLK_CSPI_CLK_ROOT:
439 		cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1);
440 		cscdr2 = bus_space_read_4(iot, ioh, CCMC_CSCDR2);
441 
442 		sel = __SHIFTOUT(cscmr1, CSCMR1_CSPI_CLK_SEL);
443 		switch (sel) {
444 		case 0:
445 		case 1:
446 		case 2:
447 			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
448 			break;
449 		case 3:
450 			freq = imx51_get_clock(IMX51CLK_LP_APM);
451 			break;
452 		}
453 
454 		freq = freq / (1 + __SHIFTOUT(cscdr2, CSCDR2_ECSPI_CLK_PRED)) /
455 		    (1 + __SHIFTOUT(cscdr2, CSCDR2_ECSPI_CLK_PODF));
456 
457 		return freq;
458 #if IMX50
459 	case IMX50CLK_PFD0_CLK_ROOT:
460 	case IMX50CLK_PFD1_CLK_ROOT:
461 	case IMX50CLK_PFD2_CLK_ROOT:
462 	case IMX50CLK_PFD3_CLK_ROOT:
463 	case IMX50CLK_PFD4_CLK_ROOT:
464 	case IMX50CLK_PFD5_CLK_ROOT:
465 	case IMX50CLK_PFD6_CLK_ROOT:
466 	case IMX50CLK_PFD7_CLK_ROOT:
467 		freq = imx51_get_pfd_freq(clk - IMX50CLK_PFD0_CLK_ROOT);
468 		return freq;
469 #endif
470 	default:
471 		aprint_error_dev(ccm_softc->sc_dev,
472 		    "clock %d: not supported yet\n", clk);
473 		return 0;
474 	}
475 }
476 
477 #ifdef IMX50
478 static uint64_t
imx51_get_pfd_freq(u_int pfd_no)479 imx51_get_pfd_freq(u_int pfd_no)
480 {
481 	return 480000000;
482 }
483 #endif
484 
485 static uint64_t
imx51_get_pll_freq(u_int pll_no)486 imx51_get_pll_freq(u_int pll_no)
487 {
488 	uint32_t dp_ctrl;
489 	uint32_t dp_op;
490 	uint32_t dp_mfd;
491 	uint32_t dp_mfn;
492 	uint32_t mfi;
493 	int32_t mfn;
494 	uint32_t mfd;
495 	uint32_t pdf;
496 	uint32_t ccr;
497 	uint64_t freq = 0;
498 	u_int ref = 0;
499 	bus_space_tag_t iot = ccm_softc->sc_iot;
500 	bus_space_handle_t ioh = ccm_softc->sc_pll[pll_no-1].pll_ioh;
501 
502 	KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS);
503 
504 	dp_ctrl = bus_space_read_4(iot, ioh, DPLL_DP_CTL);
505 
506 	if (dp_ctrl & DP_CTL_HFSM) {
507 		dp_op = bus_space_read_4(iot, ioh, DPLL_DP_HFS_OP);
508 		dp_mfd = bus_space_read_4(iot, ioh, DPLL_DP_HFS_MFD);
509 		dp_mfn = bus_space_read_4(iot, ioh, DPLL_DP_HFS_MFN);
510 	} else {
511 		dp_op = bus_space_read_4(iot, ioh, DPLL_DP_OP);
512 		dp_mfd = bus_space_read_4(iot, ioh, DPLL_DP_MFD);
513 		dp_mfn = bus_space_read_4(iot, ioh, DPLL_DP_MFN);
514 	}
515 
516 	pdf = dp_op & DP_OP_PDF;
517 	mfi = uimax(5, __SHIFTOUT(dp_op, DP_OP_MFI));
518 	mfd = dp_mfd;
519 	if (dp_mfn & __BIT(26))
520 		/* 27bit signed value */
521 		mfn = (int32_t)(__BITS(31,27) | dp_mfn);
522 	else
523 		mfn = dp_mfn;
524 
525 	switch (dp_ctrl & DP_CTL_REF_CLK_SEL) {
526 	case DP_CTL_REF_CLK_SEL_COSC:
527 		/* Internal Oscillator */
528 		ref = IMX51_OSC_FREQ;
529 		break;
530 	case DP_CTL_REF_CLK_SEL_FPM:
531 		ccr = bus_space_read_4(iot, ccm_softc->sc_ioh, CCMC_CCR);
532 		if (ccr & CCR_FPM_MULT)
533 			ref = IMX51_CKIL_FREQ * 1024;
534 		else
535 			ref = IMX51_CKIL_FREQ * 512;
536 		break;
537 	default:
538 		ref = 0;
539 	}
540 
541 
542 	if (dp_ctrl & DP_CTL_REF_CLK_DIV)
543 		ref /= 2;
544 
545 #if 0
546 	if (dp_ctrl & DP_CTL_DPDCK0_2_EN)
547 		ref *= 2;
548 
549 	ref /= (pdf + 1);
550 	freq = ref * mfn;
551 	freq /= (mfd + 1);
552 	freq = (ref * mfi) + freq;
553 #endif
554 
555 	ref *= 4;
556 	freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
557 	freq /= pdf + 1;
558 
559 	if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
560 		freq /= 2;
561 
562 
563 #ifdef IMXCCMDEBUG
564 	printf("dp_ctl: %08x ", dp_ctrl);
565 	printf("pdf: %3d ", pdf);
566 	printf("mfi: %3d ", mfi);
567 	printf("mfd: %3d ", mfd);
568 	printf("mfn: %3d ", mfn);
569 	printf("pll: %lld\n", freq);
570 #endif
571 
572 	ccm_softc->sc_pll[pll_no-1].pll_freq = freq;
573 
574 	return freq;
575 }
576 
577 void
imx51_clk_gating(int clk_src,int mode)578 imx51_clk_gating(int clk_src, int mode)
579 {
580 	bus_space_tag_t iot = ccm_softc->sc_iot;
581 	bus_space_handle_t ioh = ccm_softc->sc_ioh;
582 	uint32_t group = CCMR_CCGR_MODULE(clk_src);
583 	uint32_t field = clk_src % CCMR_CCGR_NSOURCE;
584 	uint32_t reg;
585 	uint32_t bit;
586 
587 	bit = (mode << field * 2);
588 	reg = bus_space_read_4(iot, ioh, CCMC_CCGR(group));
589 	reg &= ~(0x03 << field * 2);
590 	reg |= bit;
591 	bus_space_write_4(iot, ioh, CCMC_CCGR(group), reg);
592 
593 #ifdef IMX50
594 	switch (clk_src) {
595 	case CCGR_EPDC_AXI_CLK:
596 		reg = bus_space_read_4(iot, ioh, CCMC_EPDC_AXI);
597 		reg &= ~EPDC_AXI_CLKGATE;
598 		reg |= EPDC_AXI_CLKGATE_ALWAYS;
599 		bus_space_write_4(iot, ioh, CCMC_EPDC_AXI, reg);
600 
601 		/* enable auto-slow */
602 		reg |= EPDC_ASM_EN;
603 		reg |= __SHIFTIN(5, EPDC_ASM_SLOW_DIV);
604 		bus_space_write_4(iot, ioh, CCMC_EPDC_AXI, reg);
605 
606 		break;
607 	case CCGR_EPDC_PIX_CLK:
608 		reg = bus_space_read_4(iot, ioh, CCMC_EPDC_PIX);
609 		reg &= ~EPDC_PIX_CLKGATE;
610 		reg |= EPDC_PIX_CLKGATE_ALWAYS;
611 		bus_space_write_4(iot, ioh, CCMC_EPDC_PIX, reg);
612 
613 		break;
614 	}
615 #endif
616 }
617 
618 void
imx51_clk_rate(int clk_src,int clk_base,int rate)619 imx51_clk_rate(int clk_src, int clk_base, int rate)
620 {
621 #ifdef IMX50
622 	bus_space_tag_t iot = ccm_softc->sc_iot;
623 	bus_space_handle_t ioh = ccm_softc->sc_ioh;
624 	uint32_t reg;
625 	int div;
626 	uint64_t freq = 0;
627 
628 	switch (clk_src) {
629 	case CCGR_EPDC_AXI_CLK:
630 		reg = bus_space_read_4(iot, ioh, CCMC_CLKSEQ_BYPASS);
631 		reg &= ~CLKSEQ_EPDC_AXI_CLK;
632 		reg |= __SHIFTIN(clk_base, CLKSEQ_EPDC_AXI_CLK);
633 		bus_space_write_4(iot, ioh, CCMC_CLKSEQ_BYPASS, reg);
634 
635 		switch (clk_base) {
636 		case CLKSEQ_XTAL:
637 			freq = 24000000;
638 			break;
639 		case CLKSEQ_PFDx:
640 			freq = imx51_get_clock(IMX50CLK_PFD3_CLK_ROOT);
641 			break;
642 		case CLKSEQ_PLL1:
643 			freq = imx51_get_clock(IMX51CLK_PLL1);
644 			break;
645 		}
646 
647 		div = uimax(1, freq / rate);
648 
649 		reg = bus_space_read_4(iot, ioh, CCMC_EPDC_AXI);
650 		reg &= ~EPDC_AXI_DIV;
651 		reg |= __SHIFTIN(div, EPDC_AXI_DIV);
652 		bus_space_write_4(iot, ioh, CCMC_EPDC_AXI, reg);
653 		while (bus_space_read_4(iot, ioh, CCMC_CSR2) & CSR2_EPDC_AXI_BUSY)
654 			; /* wait */
655 		break;
656 	case CCGR_EPDC_PIX_CLK:
657 		reg = bus_space_read_4(iot, ioh, CCMC_CLKSEQ_BYPASS);
658 		reg &= ~CLKSEQ_EPDC_PIX_CLK;
659 		reg |= __SHIFTIN(clk_base, CLKSEQ_EPDC_PIX_CLK);
660 		bus_space_write_4(iot, ioh, CCMC_CLKSEQ_BYPASS, reg);
661 
662 		switch (clk_base) {
663 		case CLKSEQ_XTAL:
664 			freq = 24000000;
665 			break;
666 		case CLKSEQ_PFDx:
667 			freq = imx51_get_clock(IMX50CLK_PFD5_CLK_ROOT);
668 			break;
669 		case CLKSEQ_PLL1:
670 			freq = imx51_get_clock(IMX51CLK_PLL1);
671 			break;
672 		case CLKSEQ_CAMP1:
673 			/* XXX */
674 			freq = 0;
675 			break;
676 		}
677 
678 		div = freq / rate;
679 		reg = bus_space_read_4(iot, ioh, CCMC_EPDC_PIX);
680 		reg &= ~EPDC_PIX_CLK_PRED;
681 		reg |= __SHIFTIN(div, EPDC_PIX_CLK_PRED);
682 		bus_space_write_4(iot, ioh, CCMC_EPDC_PIX, reg);
683 		while (bus_space_read_4(iot, ioh, CCMC_CSR2) & CSR2_EPDC_PIX_BUSY)
684 			; /* wait */
685 		break;
686 	}
687 #endif
688 }
689