1 /* $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $ */
3 * Copyright (c) 2010, 2011, 2012 Genetec Corporation. All rights reserved.
4 * Written by Hashimoto Kenichi for Genetec Corporation.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 2012, 2013 The FreeBSD Foundation
30 * All rights reserved.
32 * Portions of this software were developed by Oleksandr Rybalko
33 * under sponsorship from the FreeBSD Foundation.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * Clock Controller Module (CCM)
61 #include <sys/cdefs.h>
62 __FBSDID("$FreeBSD$");
64 #include <sys/param.h>
65 #include <sys/systm.h>
67 #include <sys/kernel.h>
68 #include <sys/module.h>
69 #include <sys/malloc.h>
71 #include <machine/bus.h>
72 #include <machine/cpu.h>
73 #include <machine/intr.h>
75 #include <dev/fdt/fdt_common.h>
76 #include <dev/ofw/openfirm.h>
77 #include <dev/ofw/ofw_bus.h>
78 #include <dev/ofw/ofw_bus_subr.h>
80 #include <machine/bus.h>
81 #include <machine/fdt.h>
83 #include <arm/freescale/imx/imx51_ccmvar.h>
84 #include <arm/freescale/imx/imx51_ccmreg.h>
85 #include <arm/freescale/imx/imx51_dpllreg.h>
90 #ifndef IMX51_OSC_FREQ
91 #define IMX51_OSC_FREQ (24 * 1000 * 1000) /* 24MHz */
94 #ifndef IMX51_CKIL_FREQ
95 #define IMX51_CKIL_FREQ 32768
100 struct resource *res[7];
101 u_int64_t pll_freq[IMX51_N_DPLLS];
104 struct imxccm_softc *ccm_softc = NULL;
106 static uint64_t imx51_get_pll_freq(u_int);
108 static int imxccm_match(device_t);
109 static int imxccm_attach(device_t);
111 static device_method_t imxccm_methods[] = {
112 DEVMETHOD(device_probe, imxccm_match),
113 DEVMETHOD(device_attach, imxccm_attach),
118 static driver_t imxccm_driver = {
121 sizeof(struct imxccm_softc),
124 static devclass_t imxccm_devclass;
126 EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
129 static struct resource_spec imxccm_spec[] = {
130 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Global registers */
131 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* DPLLIP1 */
132 { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* DPLLIP2 */
133 { SYS_RES_MEMORY, 3, RF_ACTIVE }, /* DPLLIP3 */
134 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* 71 */
135 { SYS_RES_IRQ, 1, RF_ACTIVE }, /* 72 */
140 imxccm_match(device_t dev)
143 if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
144 !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
147 device_set_desc(dev, "Freescale Clock Control Module");
148 return (BUS_PROBE_DEFAULT);
152 imxccm_attach(device_t dev)
154 struct imxccm_softc *sc;
156 sc = device_get_softc(dev);
159 if (bus_alloc_resources(dev, imxccm_spec, sc->res)) {
160 device_printf(dev, "could not allocate resources\n");
166 imx51_get_pll_freq(1);
167 imx51_get_pll_freq(2);
168 imx51_get_pll_freq(3);
170 device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
171 sc->pll_freq[0] / 1000000,
172 sc->pll_freq[1] / 1000000,
173 sc->pll_freq[2] / 1000000);
174 device_printf(dev, "CPU clock=%d, UART clock=%d\n",
175 imx51_get_clock(IMX51CLK_ARM_ROOT),
176 imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
178 "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
179 imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
180 imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
181 imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
182 imx51_get_clock(IMX51CLK_PERCLK_ROOT));
189 imx51_get_clock(enum imx51_clock clk)
193 uint32_t cacrr; /* ARM clock root register */
201 if (ccm_softc == NULL)
208 return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
209 case IMX51CLK_PLL1SW:
210 ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
211 if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
212 return ccm_softc->pll_freq[1-1];
215 case IMX51CLK_PLL1STEP:
216 ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
217 switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
219 return imx51_get_clock(IMX51CLK_LP_APM);
221 return 0; /* XXX PLL bypass clock */
223 return ccm_softc->pll_freq[2-1] /
224 (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
225 CCSR_PLL2_DIV_PODF_SHIFT));
227 return ccm_softc->pll_freq[3-1] /
228 (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
229 CCSR_PLL3_DIV_PODF_SHIFT));
232 case IMX51CLK_PLL2SW:
233 ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
234 if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
235 return imx51_get_clock(IMX51CLK_PLL2);
236 return 0; /* XXX PLL2 bypass clk */
237 case IMX51CLK_PLL3SW:
238 ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
239 if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
240 return imx51_get_clock(IMX51CLK_PLL3);
241 return 0; /* XXX PLL3 bypass clk */
243 case IMX51CLK_LP_APM:
244 ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
245 return (ccsr & CCSR_LP_APM) ?
246 imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
248 case IMX51CLK_ARM_ROOT:
249 freq = imx51_get_clock(IMX51CLK_PLL1SW);
250 cacrr = bus_read_4(ccm_softc->res[0], CCMC_CACRR);
251 return freq / (cacrr + 1);
254 case IMX51CLK_MAIN_BUS_CLK_SRC:
255 cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
256 if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
257 freq = imx51_get_clock(IMX51CLK_PLL2SW);
260 cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR);
261 switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
262 CBCMR_PERIPH_APM_SEL_SHIFT) {
264 freq = imx51_get_clock(IMX51CLK_PLL1SW);
267 freq = imx51_get_clock(IMX51CLK_PLL3SW);
270 freq = imx51_get_clock(IMX51CLK_LP_APM);
278 case IMX51CLK_MAIN_BUS_CLK:
279 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
280 cdcr = bus_read_4(ccm_softc->res[0], CCMC_CDCR);
281 return freq / (cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
282 CDCR_PERIPH_CLK_DVFS_PODF_SHIFT;
283 case IMX51CLK_AHB_CLK_ROOT:
284 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
285 cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
286 return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
287 CBCDR_AHB_PODF_SHIFT));
288 case IMX51CLK_IPG_CLK_ROOT:
289 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
290 cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
291 return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
292 CBCDR_IPG_PODF_SHIFT));
294 case IMX51CLK_PERCLK_ROOT:
295 cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR);
296 if (cbcmr & CBCMR_PERCLK_IPG_SEL)
297 return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
298 if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
299 freq = imx51_get_clock(IMX51CLK_LP_APM);
301 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
302 cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
305 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
308 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
309 CBCDR_PERCLK_PRED1_SHIFT);
310 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
311 CBCDR_PERCLK_PRED2_SHIFT);
312 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
313 CBCDR_PERCLK_PODF_SHIFT);
315 case IMX51CLK_UART_CLK_ROOT:
316 cscdr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCDR1);
317 cscmr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1);
320 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
323 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
324 CSCMR1_UART_CLK_SEL_SHIFT;
326 freq = 0; /* shut up GCC */
331 freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
334 freq = imx51_get_clock(IMX51CLK_LP_APM);
338 return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
339 CSCDR1_UART_CLK_PRED_SHIFT)) /
340 (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
341 CSCDR1_UART_CLK_PODF_SHIFT));
342 case IMX51CLK_IPU_HSP_CLK_ROOT:
344 cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR);
345 switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
346 CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
348 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
351 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
354 freq = imx51_get_clock(
355 IMX51CLK_EMI_SLOW_CLK_ROOT);
358 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
363 device_printf(ccm_softc->sc_dev,
364 "clock %d: not supported yet\n", clk);
371 imx51_get_pll_freq(u_int pll_no)
385 KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
387 dp_ctrl = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_CTL);
389 if (dp_ctrl & DP_CTL_HFSM) {
390 dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_OP);
391 dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFD);
392 dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFN);
394 dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_OP);
395 dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFD);
396 dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFN);
399 pdf = dp_op & DP_OP_PDF_MASK;
400 mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
402 if (dp_mfn & 0x04000000)
403 /* 27bit signed value */
404 mfn = (uint32_t)(0xf8000000 | dp_mfn);
408 switch (dp_ctrl & DP_CTL_REF_CLK_SEL_MASK) {
409 case DP_CTL_REF_CLK_SEL_COSC:
410 /* Internal Oscillator */
411 /* TODO: get from FDT "fsl,imx-osc" */
412 ref = 24000000; /* IMX51_OSC_FREQ */
414 case DP_CTL_REF_CLK_SEL_FPM:
415 ccr = bus_read_4(ccm_softc->res[0], CCMC_CCR);
416 if (ccr & CCR_FPM_MULT)
417 /* TODO: get from FDT "fsl,imx-ckil" */
420 /* TODO: get from FDT "fsl,imx-ckil" */
427 if (dp_ctrl & DP_CTL_REF_CLK_DIV)
431 freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
434 if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
438 printf("ref: %dKHz ", ref);
439 printf("dp_ctl: %08x ", dp_ctrl);
440 printf("pdf: %3d ", pdf);
441 printf("mfi: %3d ", mfi);
442 printf("mfd: %3d ", mfd);
443 printf("mfn: %3d ", mfn);
444 printf("pll: %d\n", (uint32_t)freq);
447 ccm_softc->pll_freq[pll_no-1] = freq;
453 imx51_clk_gating(int clk_src, int mode)
458 group = CCMR_CCGR_MODULE(clk_src);
459 field = clk_src % CCMR_CCGR_NSOURCE;
460 reg = bus_read_4(ccm_softc->res[0], CCMC_CCGR(group));
461 reg &= ~(0x03 << field * 2);
462 reg |= (mode << field * 2);
463 bus_write_4(ccm_softc->res[0], CCMC_CCGR(group), reg);
467 imx51_get_clk_gating(int clk_src)
471 reg = bus_read_4(ccm_softc->res[0],
472 CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
473 return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);