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