]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/arm/freescale/imx/imx51_ccm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  * Copyright (c) 2010, 2011, 2012  Genetec Corporation.  All rights reserved.
4  * Written by Hashimoto Kenichi for Genetec Corporation.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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.
26  */
27
28 /*-
29  * Copyright (c) 2012, 2013 The FreeBSD Foundation
30  * All rights reserved.
31  *
32  * Portions of this software were developed by Oleksandr Rybalko
33  * under sponsorship from the FreeBSD Foundation.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
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.
43  *
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
54  * SUCH DAMAGE.
55  */
56
57 /*
58  * Clock Controller Module (CCM)
59  */
60
61 #include <sys/cdefs.h>
62 __FBSDID("$FreeBSD$");
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/bus.h>
67 #include <sys/kernel.h>
68 #include <sys/module.h>
69 #include <sys/malloc.h>
70 #include <sys/rman.h>
71 #include <machine/bus.h>
72 #include <machine/cpu.h>
73 #include <machine/intr.h>
74
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>
79
80 #include <machine/bus.h>
81 #include <machine/fdt.h>
82
83 #include <arm/freescale/imx/imx51_ccmvar.h>
84 #include <arm/freescale/imx/imx51_ccmreg.h>
85 #include <arm/freescale/imx/imx51_dpllreg.h>
86
87 #define IMXCCMDEBUG
88 #undef  IMXCCMDEBUG
89
90 #ifndef IMX51_OSC_FREQ
91 #define IMX51_OSC_FREQ  (24 * 1000 * 1000)      /* 24MHz */
92 #endif
93
94 #ifndef IMX51_CKIL_FREQ
95 #define IMX51_CKIL_FREQ 32768
96 #endif
97
98 struct imxccm_softc {
99         device_t        sc_dev;
100         struct resource *res[7];
101         u_int64_t       pll_freq[IMX51_N_DPLLS];
102 };
103
104 struct imxccm_softc *ccm_softc = NULL;
105
106 static uint64_t imx51_get_pll_freq(u_int);
107
108 static int imxccm_match(device_t);
109 static int imxccm_attach(device_t);
110
111 static device_method_t imxccm_methods[] = {
112         DEVMETHOD(device_probe, imxccm_match),
113         DEVMETHOD(device_attach, imxccm_attach),
114
115         DEVMETHOD_END
116 };
117
118 static driver_t imxccm_driver = {
119         "imxccm",
120         imxccm_methods,
121         sizeof(struct imxccm_softc),
122 };
123
124 static devclass_t imxccm_devclass;
125
126 EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
127     BUS_PASS_CPU);
128
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 */
136         { -1, 0 }
137 };
138
139 static int
140 imxccm_match(device_t dev)
141 {
142
143         if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
144             !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
145                 return (ENXIO);
146
147         device_set_desc(dev, "Freescale Clock Control Module");
148         return (BUS_PROBE_DEFAULT);
149 }
150
151 static int
152 imxccm_attach(device_t dev)
153 {
154         struct imxccm_softc *sc;
155
156         sc = device_get_softc(dev);
157         sc->sc_dev = dev;
158
159         if (bus_alloc_resources(dev, imxccm_spec, sc->res)) {
160                 device_printf(dev, "could not allocate resources\n");
161                 return (ENXIO);
162         }
163
164         ccm_softc = sc;
165
166         imx51_get_pll_freq(1);
167         imx51_get_pll_freq(2);
168         imx51_get_pll_freq(3);
169
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));
177         device_printf(dev,
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));
183
184
185         return (0);
186 }
187
188 u_int
189 imx51_get_clock(enum imx51_clock clk)
190 {
191         u_int freq;
192         u_int sel;
193         uint32_t cacrr; /* ARM clock root register */
194         uint32_t ccsr;
195         uint32_t cscdr1;
196         uint32_t cscmr1;
197         uint32_t cbcdr;
198         uint32_t cbcmr;
199         uint32_t cdcr;
200
201         if (ccm_softc == NULL)
202                 return (0);
203
204         switch (clk) {
205         case IMX51CLK_PLL1:
206         case IMX51CLK_PLL2:
207         case IMX51CLK_PLL3:
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];
213                 /* step clock */
214                 /* FALLTHROUGH */
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) {
218                 case 0:
219                         return imx51_get_clock(IMX51CLK_LP_APM);
220                 case 1:
221                         return 0; /* XXX PLL bypass clock */
222                 case 2:
223                         return ccm_softc->pll_freq[2-1] /
224                             (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
225                                 CCSR_PLL2_DIV_PODF_SHIFT));
226                 case 3:
227                         return ccm_softc->pll_freq[3-1] /
228                             (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
229                                 CCSR_PLL3_DIV_PODF_SHIFT));
230                 }
231                 /*NOTREACHED*/
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 */
242
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;
247
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);
252
253                 /* ... */
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);
258                 else {
259                         freq = 0;
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) {
263                         case 0:
264                                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
265                                 break;
266                         case 1:
267                                 freq = imx51_get_clock(IMX51CLK_PLL3SW);
268                                 break;
269                         case 2:
270                                 freq = imx51_get_clock(IMX51CLK_LP_APM);
271                                 break;
272                         case 3:
273                                 /* XXX: error */
274                                 break;
275                         }
276                 }
277                 return freq;
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));
293
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);
300                 else
301                         freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
302                 cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
303
304 #ifdef IMXCCMDEBUG
305                 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
306 #endif
307
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);
314                 return freq;
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);
318
319 #ifdef IMXCCMDEBUG
320                 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
321 #endif
322
323                 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
324                     CSCMR1_UART_CLK_SEL_SHIFT;
325
326                 freq = 0; /* shut up GCC */
327                 switch (sel) {
328                 case 0:
329                 case 1:
330                 case 2:
331                         freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
332                         break;
333                 case 3:
334                         freq = imx51_get_clock(IMX51CLK_LP_APM);
335                         break;
336                 }
337
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:
343                 freq = 0;
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) {
347                         case 0:
348                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
349                                 break;
350                         case 1:
351                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
352                                 break;
353                         case 2:
354                                 freq = imx51_get_clock(
355                                         IMX51CLK_EMI_SLOW_CLK_ROOT);
356                                 break;
357                         case 3:
358                                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
359                                 break;
360                         }
361                 return freq;
362         default:
363                 device_printf(ccm_softc->sc_dev,
364                     "clock %d: not supported yet\n", clk);
365                 return 0;
366         }
367 }
368
369
370 static uint64_t
371 imx51_get_pll_freq(u_int pll_no)
372 {
373         uint32_t dp_ctrl;
374         uint32_t dp_op;
375         uint32_t dp_mfd;
376         uint32_t dp_mfn;
377         uint32_t mfi;
378         int32_t mfn;
379         uint32_t mfd;
380         uint32_t pdf;
381         uint32_t ccr;
382         uint64_t freq = 0;
383         u_int ref = 0;
384
385         KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
386
387         dp_ctrl = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_CTL);
388
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);
393         } else {
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);
397         }
398
399         pdf = dp_op & DP_OP_PDF_MASK;
400         mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
401         mfd = dp_mfd;
402         if (dp_mfn & 0x04000000)
403                 /* 27bit signed value */
404                 mfn = (uint32_t)(0xf8000000 | dp_mfn);
405         else
406                 mfn = dp_mfn;
407
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 */
413                 break;
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" */
418                         ref = 32768 * 1024;
419                 else
420                 /* TODO: get from FDT "fsl,imx-ckil" */
421                         ref = 32768 * 512;
422                 break;
423         default:
424                 ref = 0;
425         }
426
427         if (dp_ctrl & DP_CTL_REF_CLK_DIV)
428                 ref /= 2;
429
430         ref *= 4;
431         freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
432         freq /= pdf + 1;
433
434         if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
435                 freq /= 2;
436
437 #ifdef IMXCCMDEBUG
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);
445 #endif
446
447         ccm_softc->pll_freq[pll_no-1] = freq;
448
449         return (freq);
450 }
451
452 void
453 imx51_clk_gating(int clk_src, int mode)
454 {
455         int field, group;
456         uint32_t reg;
457
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);
464 }
465
466 int
467 imx51_get_clk_gating(int clk_src)
468 {
469         uint32_t reg;
470
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);
474 }
475