]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/freescale/imx/imx51_ccm.c
Merge libcxxrt master f96846efbfd508f66d91fcbbef5dd808947c7f6d.
[FreeBSD/FreeBSD.git] / sys / arm / freescale / imx / imx51_ccm.c
1 /*      $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $        */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause AND BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2010, 2011, 2012  Genetec Corporation.  All rights reserved.
6  * Written by Hashimoto Kenichi for Genetec Corporation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 /*-
31  * Copyright (c) 2012, 2013 The FreeBSD Foundation
32  * All rights reserved.
33  *
34  * Portions of this software were developed by Oleksandr Rybalko
35  * under sponsorship from the FreeBSD Foundation.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1.   Redistributions of source code must retain the above copyright
41  *      notice, this list of conditions and the following disclaimer.
42  * 2.   Redistributions in binary form must reproduce the above copyright
43  *      notice, this list of conditions and the following disclaimer in the
44  *      documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58
59 /*
60  * Clock Controller Module (CCM)
61  */
62
63 #include <sys/cdefs.h>
64 __FBSDID("$FreeBSD$");
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/bus.h>
69 #include <sys/kernel.h>
70 #include <sys/module.h>
71 #include <sys/malloc.h>
72 #include <sys/rman.h>
73 #include <machine/bus.h>
74 #include <machine/cpu.h>
75 #include <machine/intr.h>
76
77 #include <dev/ofw/openfirm.h>
78 #include <dev/ofw/ofw_bus.h>
79 #include <dev/ofw/ofw_bus_subr.h>
80
81 #include <machine/bus.h>
82 #include <machine/fdt.h>
83
84 #include <arm/freescale/imx/imx51_ccmvar.h>
85 #include <arm/freescale/imx/imx51_ccmreg.h>
86 #include <arm/freescale/imx/imx51_dpllreg.h>
87 #include <arm/freescale/imx/imx_ccmvar.h>
88 #include <arm/freescale/imx/imx_machdep.h>
89
90 #define IMXCCMDEBUG
91 #undef  IMXCCMDEBUG
92
93 #ifndef IMX51_OSC_FREQ
94 #define IMX51_OSC_FREQ  (24 * 1000 * 1000)      /* 24MHz */
95 #endif
96
97 #ifndef IMX51_CKIL_FREQ
98 #define IMX51_CKIL_FREQ 32768
99 #endif
100
101 /*
102  * The fdt data does not provide reg properties describing the DPLL register
103  * blocks we need to access, presumably because the needed addresses are
104  * hard-coded within the linux driver.  That leaves us with no choice but to do
105  * the same thing, if we want to run with vendor-supplied fdt data.  So here we
106  * have tables of the physical addresses we need for each soc, and we'll use
107  * bus_space_map() at attach() time to get access to them.
108  */
109 static uint32_t imx51_dpll_addrs[IMX51_N_DPLLS] = {
110         0x83f80000,     /* DPLL1 */
111         0x83f84000,     /* DPLL2 */
112         0x83f88000,     /* DPLL3 */
113 };
114
115 static uint32_t imx53_dpll_addrs[IMX51_N_DPLLS] = {
116         0x63f80000,     /* DPLL1 */
117         0x63f84000,     /* DPLL2 */
118         0x63f88000,     /* DPLL3 */
119 };
120
121 #define DPLL_REGS_SZ    (16 * 1024)
122
123 struct imxccm_softc {
124         device_t        sc_dev;
125         struct resource *ccmregs;
126         u_int64_t       pll_freq[IMX51_N_DPLLS];
127         bus_space_tag_t    pllbst;
128         bus_space_handle_t pllbsh[IMX51_N_DPLLS];
129 };
130
131 struct imxccm_softc *ccm_softc = NULL;
132
133 static uint64_t imx51_get_pll_freq(u_int);
134
135 static int imxccm_match(device_t);
136 static int imxccm_attach(device_t);
137
138 static device_method_t imxccm_methods[] = {
139         DEVMETHOD(device_probe, imxccm_match),
140         DEVMETHOD(device_attach, imxccm_attach),
141
142         DEVMETHOD_END
143 };
144
145 static driver_t imxccm_driver = {
146         "imxccm",
147         imxccm_methods,
148         sizeof(struct imxccm_softc),
149 };
150
151 static devclass_t imxccm_devclass;
152
153 EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
154     BUS_PASS_CPU);
155
156 static inline uint32_t
157 pll_read_4(struct imxccm_softc *sc, int pll, int reg)
158 {
159
160         return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg));
161 }
162
163 static inline uint32_t
164 ccm_read_4(struct imxccm_softc *sc, int reg)
165 {
166
167         return (bus_read_4(sc->ccmregs, reg));
168 }
169
170 static inline void
171 ccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val)
172 {
173
174         bus_write_4(sc->ccmregs, reg, val);
175 }
176
177 static int
178 imxccm_match(device_t dev)
179 {
180
181         if (!ofw_bus_status_okay(dev))
182                 return (ENXIO);
183
184         if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
185             !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
186                 return (ENXIO);
187
188         device_set_desc(dev, "Freescale Clock Control Module");
189         return (BUS_PROBE_DEFAULT);
190 }
191
192 static int
193 imxccm_attach(device_t dev)
194 {
195         struct imxccm_softc *sc;
196         int idx;
197         u_int soc;
198         uint32_t *pll_addrs;
199
200         sc = device_get_softc(dev);
201         sc->sc_dev = dev;
202
203         switch ((soc = imx_soc_type())) {
204         case IMXSOC_51:
205                 pll_addrs = imx51_dpll_addrs;
206                 break;
207         case IMXSOC_53:
208                 pll_addrs = imx53_dpll_addrs;
209                 break;
210         default:
211                 device_printf(dev, "No support for SoC type 0x%08x\n", soc);
212                 goto noclocks;
213         }
214
215         idx = 0;
216         sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx,
217             RF_ACTIVE);
218         if (sc->ccmregs == NULL) {
219                 device_printf(dev, "could not allocate resources\n");
220                 goto noclocks;
221         }
222
223         sc->pllbst = fdtbus_bs_tag;
224         for (idx = 0; idx < IMX51_N_DPLLS; ++idx) {
225                 if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0,
226                     &sc->pllbsh[idx]) != 0) {
227                         device_printf(dev, "Cannot map DPLL registers\n");
228                         goto noclocks;
229                 }
230         }
231
232         ccm_softc = sc;
233
234         imx51_get_pll_freq(1);
235         imx51_get_pll_freq(2);
236         imx51_get_pll_freq(3);
237
238         device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
239             sc->pll_freq[0] / 1000000,
240             sc->pll_freq[1] / 1000000,
241             sc->pll_freq[2] / 1000000);
242         device_printf(dev, "CPU clock=%d, UART clock=%d\n",
243             imx51_get_clock(IMX51CLK_ARM_ROOT),
244             imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
245         device_printf(dev,
246             "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
247             imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
248             imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
249             imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
250             imx51_get_clock(IMX51CLK_PERCLK_ROOT));
251
252
253         return (0);
254
255 noclocks:
256
257         panic("Cannot continue without clock support");
258 }
259
260 u_int
261 imx51_get_clock(enum imx51_clock clk)
262 {
263         u_int freq;
264         u_int sel;
265         uint32_t cacrr; /* ARM clock root register */
266         uint32_t ccsr;
267         uint32_t cscdr1;
268         uint32_t cscmr1;
269         uint32_t cbcdr;
270         uint32_t cbcmr;
271         uint32_t cdcr;
272
273         if (ccm_softc == NULL)
274                 return (0);
275
276         switch (clk) {
277         case IMX51CLK_PLL1:
278         case IMX51CLK_PLL2:
279         case IMX51CLK_PLL3:
280                 return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
281         case IMX51CLK_PLL1SW:
282                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
283                 if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
284                         return ccm_softc->pll_freq[1-1];
285                 /* step clock */
286                 /* FALLTHROUGH */
287         case IMX51CLK_PLL1STEP:
288                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
289                 switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
290                 case 0:
291                         return imx51_get_clock(IMX51CLK_LP_APM);
292                 case 1:
293                         return 0; /* XXX PLL bypass clock */
294                 case 2:
295                         return ccm_softc->pll_freq[2-1] /
296                             (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
297                                 CCSR_PLL2_DIV_PODF_SHIFT));
298                 case 3:
299                         return ccm_softc->pll_freq[3-1] /
300                             (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
301                                 CCSR_PLL3_DIV_PODF_SHIFT));
302                 }
303                 /*NOTREACHED*/
304         case IMX51CLK_PLL2SW:
305                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
306                 if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
307                         return imx51_get_clock(IMX51CLK_PLL2);
308                 return 0; /* XXX PLL2 bypass clk */
309         case IMX51CLK_PLL3SW:
310                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
311                 if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
312                         return imx51_get_clock(IMX51CLK_PLL3);
313                 return 0; /* XXX PLL3 bypass clk */
314
315         case IMX51CLK_LP_APM:
316                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
317                 return (ccsr & CCSR_LP_APM) ?
318                             imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
319
320         case IMX51CLK_ARM_ROOT:
321                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
322                 cacrr = ccm_read_4(ccm_softc, CCMC_CACRR);
323                 return freq / (cacrr + 1);
324
325                 /* ... */
326         case IMX51CLK_MAIN_BUS_CLK_SRC:
327                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
328                 if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
329                         freq = imx51_get_clock(IMX51CLK_PLL2SW);
330                 else {
331                         freq = 0;
332                         cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
333                         switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
334                                 CBCMR_PERIPH_APM_SEL_SHIFT) {
335                         case 0:
336                                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
337                                 break;
338                         case 1:
339                                 freq = imx51_get_clock(IMX51CLK_PLL3SW);
340                                 break;
341                         case 2:
342                                 freq = imx51_get_clock(IMX51CLK_LP_APM);
343                                 break;
344                         case 3:
345                                 /* XXX: error */
346                                 break;
347                         }
348                 }
349                 return freq;
350         case IMX51CLK_MAIN_BUS_CLK:
351                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
352                 cdcr = ccm_read_4(ccm_softc, CCMC_CDCR);
353                 return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
354                         CDCR_PERIPH_CLK_DVFS_PODF_SHIFT));
355         case IMX51CLK_AHB_CLK_ROOT:
356                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
357                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
358                 return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
359                                     CBCDR_AHB_PODF_SHIFT));
360         case IMX51CLK_IPG_CLK_ROOT:
361                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
362                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
363                 return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
364                                     CBCDR_IPG_PODF_SHIFT));
365
366         case IMX51CLK_PERCLK_ROOT:
367                 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR);
368                 if (cbcmr & CBCMR_PERCLK_IPG_SEL)
369                         return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
370                 if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
371                         freq = imx51_get_clock(IMX51CLK_LP_APM);
372                 else
373                         freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
374                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
375
376 #ifdef IMXCCMDEBUG
377                 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
378 #endif
379
380                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
381                         CBCDR_PERCLK_PRED1_SHIFT);
382                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
383                         CBCDR_PERCLK_PRED2_SHIFT);
384                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
385                         CBCDR_PERCLK_PODF_SHIFT);
386                 return freq;
387         case IMX51CLK_UART_CLK_ROOT:
388                 cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1);
389                 cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1);
390
391 #ifdef IMXCCMDEBUG
392                 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
393 #endif
394
395                 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
396                     CSCMR1_UART_CLK_SEL_SHIFT;
397
398                 freq = 0; /* shut up GCC */
399                 switch (sel) {
400                 case 0:
401                 case 1:
402                 case 2:
403                         freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
404                         break;
405                 case 3:
406                         freq = imx51_get_clock(IMX51CLK_LP_APM);
407                         break;
408                 }
409
410                 return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
411                         CSCDR1_UART_CLK_PRED_SHIFT)) /
412                     (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
413                         CSCDR1_UART_CLK_PODF_SHIFT));
414         case IMX51CLK_IPU_HSP_CLK_ROOT:
415                 freq = 0;
416                 cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
417                 switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
418                                 CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
419                         case 0:
420                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
421                                 break;
422                         case 1:
423                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
424                                 break;
425                         case 2:
426                                 freq = imx51_get_clock(
427                                         IMX51CLK_EMI_SLOW_CLK_ROOT);
428                                 break;
429                         case 3:
430                                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
431                                 break;
432                         }
433                 return freq;
434         default:
435                 device_printf(ccm_softc->sc_dev,
436                     "clock %d: not supported yet\n", clk);
437                 return 0;
438         }
439 }
440
441
442 static uint64_t
443 imx51_get_pll_freq(u_int pll_no)
444 {
445         uint32_t dp_ctrl;
446         uint32_t dp_op;
447         uint32_t dp_mfd;
448         uint32_t dp_mfn;
449         uint32_t mfi;
450         int32_t mfn;
451         uint32_t mfd;
452         uint32_t pdf;
453         uint32_t ccr;
454         uint64_t freq = 0;
455         u_int ref = 0;
456
457         KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
458
459         dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL);
460
461         if (dp_ctrl & DP_CTL_HFSM) {
462                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP);
463                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD);
464                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN);
465         } else {
466                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP);
467                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD);
468                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN);
469         }
470
471         pdf = dp_op & DP_OP_PDF_MASK;
472         mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
473         mfd = dp_mfd;
474         if (dp_mfn & 0x04000000)
475                 /* 27bit signed value */
476                 mfn = (uint32_t)(0xf8000000 | dp_mfn);
477         else
478                 mfn = dp_mfn;
479
480         switch (dp_ctrl &  DP_CTL_REF_CLK_SEL_MASK) {
481         case DP_CTL_REF_CLK_SEL_COSC:
482                 /* Internal Oscillator */
483                 /* TODO: get from FDT "fsl,imx-osc" */
484                 ref = 24000000; /* IMX51_OSC_FREQ */
485                 break;
486         case DP_CTL_REF_CLK_SEL_FPM:
487                 ccr = ccm_read_4(ccm_softc, CCMC_CCR);
488                 if (ccr & CCR_FPM_MULT)
489                 /* TODO: get from FDT "fsl,imx-ckil" */
490                         ref = 32768 * 1024;
491                 else
492                 /* TODO: get from FDT "fsl,imx-ckil" */
493                         ref = 32768 * 512;
494                 break;
495         default:
496                 ref = 0;
497         }
498
499         if (dp_ctrl & DP_CTL_REF_CLK_DIV)
500                 ref /= 2;
501
502         ref *= 4;
503         freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
504         freq /= pdf + 1;
505
506         if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
507                 freq /= 2;
508
509 #ifdef IMXCCMDEBUG
510         printf("ref: %dKHz ", ref);
511         printf("dp_ctl: %08x ", dp_ctrl);
512         printf("pdf: %3d ", pdf);
513         printf("mfi: %3d ", mfi);
514         printf("mfd: %3d ", mfd);
515         printf("mfn: %3d ", mfn);
516         printf("pll: %d\n", (uint32_t)freq);
517 #endif
518
519         ccm_softc->pll_freq[pll_no-1] = freq;
520
521         return (freq);
522 }
523
524 void
525 imx51_clk_gating(int clk_src, int mode)
526 {
527         int field, group;
528         uint32_t reg;
529
530         group = CCMR_CCGR_MODULE(clk_src);
531         field = clk_src % CCMR_CCGR_NSOURCE;
532         reg = ccm_read_4(ccm_softc, CCMC_CCGR(group));
533         reg &= ~(0x03 << field * 2);
534         reg |= (mode << field * 2);
535         ccm_write_4(ccm_softc, CCMC_CCGR(group), reg);
536 }
537
538 int
539 imx51_get_clk_gating(int clk_src)
540 {
541         uint32_t reg;
542
543         reg = ccm_read_4(ccm_softc,
544             CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
545         return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);
546 }
547
548 /*
549  * Code from here down is temporary, in lieu of a SoC-independent clock API.
550  */
551
552 void
553 imx_ccm_usb_enable(device_t dev)
554 {
555         uint32_t regval;
556
557         /*
558          * Select PLL2 as the source for the USB clock.
559          * The default is PLL3, but U-boot changes it to PLL2.
560          */
561         regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
562         regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK;
563         regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT;
564         ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
565
566         /*
567          * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2.
568          */
569         regval = ccm_read_4(ccm_softc, CCMC_CSCDR1);
570         regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK;
571         regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK;
572         regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT;
573         regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT;
574         ccm_write_4(ccm_softc, CCMC_CSCDR1, regval);
575
576         /*
577          * The same two clocks gates are used on imx51 and imx53.
578          */
579         imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS);
580         imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS);
581 }
582
583 void
584 imx_ccm_usbphy_enable(device_t dev)
585 {
586         uint32_t regval;
587
588         /*
589          * Select PLL3 as the source for the USBPHY clock.  U-boot does this 
590          * only for imx53, but the bit exists on imx51.  That seems a bit
591          * strange, but we'll go with it until more is known.
592          */
593         if (imx_soc_type() == IMXSOC_53) {
594                 regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
595                 regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT;
596                 ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
597         }
598
599         /*
600          * For the imx51 there's just one phy gate control, enable it.
601          */
602         if (imx_soc_type() == IMXSOC_51) {
603                 imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS);
604                 return;
605         }
606
607         /*
608          * For imx53 we don't have a full set of clock defines yet, but the
609          * datasheet says:
610          *   gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable)
611          *   gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable)
612          *
613          * We should use the fdt data for the device to figure out which of
614          * the two we're working on, but for now just turn them both on.
615          */
616         if (imx_soc_type() == IMXSOC_53) {
617                 imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS);
618                 imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS);
619                 return;
620         }
621 }
622
623 uint32_t
624 imx_ccm_ecspi_hz(void)
625 {
626
627         return (imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT));
628 }
629
630 uint32_t
631 imx_ccm_ipg_hz(void)
632 {
633
634         return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT));
635 }
636
637 uint32_t
638 imx_ccm_sdhci_hz(void)
639 {
640
641         return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
642 }
643
644 uint32_t
645 imx_ccm_perclk_hz(void)
646 {
647
648         return (imx51_get_clock(IMX51CLK_PERCLK_ROOT));
649 }
650
651 uint32_t
652 imx_ccm_uart_hz(void)
653 {
654
655         return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
656 }
657
658 uint32_t
659 imx_ccm_ahb_hz(void)
660 {
661
662         return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT));
663 }
664