imx6_ccm.c revision 1.2 1 /* $NetBSD: imx6_ccm.c,v 1.2 2022/09/27 06:36:42 skrll 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 * Clock Controller Module (CCM) for i.MX6
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: imx6_ccm.c,v 1.2 2022/09/27 06:36:42 skrll Exp $");
34
35 #include "opt_imx.h"
36 #include "opt_cputypes.h"
37
38 #include "locators.h"
39
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/bus.h>
43 #include <sys/device.h>
44 #include <sys/sysctl.h>
45 #include <sys/cpufreq.h>
46 #include <sys/param.h>
47
48 #include <machine/cpu.h>
49
50 #include <arm/nxp/imx6_ccmvar.h>
51 #include <arm/nxp/imx6_ccmreg.h>
52
53 #include <dev/clk/clk_backend.h>
54
55 /* Clock Parents Tables */
56 static const char *step_p[] = {
57 "osc",
58 "pll2_pfd2_396m"
59 };
60
61 static const char *pll1_sw_p[] = {
62 "pll1_sys",
63 "step"
64 };
65
66 static const char *periph_pre_p[] = {
67 "pll2_bus",
68 "pll2_pfd2_396m",
69 "pll2_pfd0_352m",
70 "pll2_198m"
71 };
72
73 static const char *periph_clk2_p[] = {
74 "pll3_usb_otg",
75 "osc",
76 "osc",
77 "dummy"
78 };
79
80 static const char *periph2_clk2_p[] = {
81 "pll3_usb_otg",
82 "pll2_bus"
83 };
84
85 static const char *axi_p[] = {
86 "periph",
87 "pll2_pfd2_396m",
88 "periph",
89 "pll3_pfd1_540m"
90 };
91
92 static const char *audio_p[] = {
93 "pll4_audio_div",
94 "pll3_pfd2_508m",
95 "pll3_pfd3_454m",
96 "pll3_usb_otg"
97 };
98
99 static const char *gpu2d_core_p[] = {
100 "axi",
101 "pll3_usb_otg",
102 "pll2_pfd0_352m",
103 "pll2_pfd2_396m"
104 };
105
106 static const char *gpu3d_core_p[] = {
107 "mmdc_ch0_axi",
108 "pll3_usb_otg",
109 "pll2_pfd1_594m",
110 "pll2_pfd2_396m"
111 };
112
113 static const char *gpu3d_shader_p[] = {
114 "mmdc_ch0_axi",
115 "pll3_usb_otg",
116 "pll2_pfd1_594m",
117 "pll3_pfd0_720m"
118 };
119
120 static const char *ipu_p[] = {
121 "mmdc_ch0_axi",
122 "pll2_pfd2_396m",
123 "pll3_120m",
124 "pll3_pfd1_540m"
125 };
126
127 static const char *pll_bypass_src_p[] = {
128 "osc",
129 "lvds1_in",
130 "lvds2_in",
131 "dummy"
132 };
133
134 static const char *pll1_bypass_p[] = {
135 "pll1",
136 "pll1_bypass_src"
137 };
138
139 static const char *pll2_bypass_p[] = {
140 "pll2",
141 "pll2_bypass_src"
142 };
143
144 static const char *pll3_bypass_p[] = {
145 "pll3",
146 "pll3_bypass_src"
147 };
148
149 static const char *pll4_bypass_p[] = {
150 "pll4",
151 "pll4_bypass_src"
152 };
153
154 static const char *pll5_bypass_p[] = {
155 "pll5",
156 "pll5_bypass_src"
157 };
158
159 static const char *pll6_bypass_p[] = {
160 "pll6",
161 "pll6_bypass_src"
162 };
163
164 static const char *pll7_bypass_p[] = {
165 "pll7",
166 "pll7_bypass_src"
167 };
168
169 static const char *ipu_di_pre_p[] = {
170 "mmdc_ch0_axi",
171 "pll3_usb_otg",
172 "pll5_video_div",
173 "pll2_pfd0_352m",
174 "pll2_pfd2_396m",
175 "pll3_pfd1_540m"
176 };
177
178 static const char *ipu1_di0_p[] = {
179 "ipu1_di0_pre",
180 "dummy",
181 "dummy",
182 "ldb_di0",
183 "ldb_di1"
184 };
185
186 static const char *ipu1_di1_p[] = {
187 "ipu1_di1_pre",
188 "dummy",
189 "dummy",
190 "ldb_di0",
191 "ldb_di1"
192 };
193
194 static const char *ipu2_di0_p[] = {
195 "ipu2_di0_pre",
196 "dummy",
197 "dummy",
198 "ldb_di0",
199 "ldb_di1"
200 };
201
202 static const char *ipu2_di1_p[] = {
203 "ipu2_di1_pre",
204 "dummy",
205 "dummy",
206 "ldb_di0",
207 "ldb_di1"
208 };
209
210 static const char *ldb_di_p[] = {
211 "pll5_video_div",
212 "pll2_pfd0_352m",
213 "pll2_pfd2_396m",
214 "mmdc_ch1_axi",
215 "pll3_usb_otg"
216 };
217
218 static const char *periph_p[] = {
219 "periph_pre",
220 "periph_clk2"
221 };
222
223 static const char *periph2_p[] = {
224 "periph2_pre",
225 "periph2_clk2"
226 };
227
228 static const char *vdo_axi_p[] = {
229 "axi",
230 "ahb"
231 };
232
233 static const char *vpu_axi_p[] = {
234 "axi",
235 "pll2_pfd2_396m",
236 "pll2_pfd0_352m"
237 };
238
239 static const char *cko1_p[] = {
240 "pll3_usb_otg",
241 "pll2_bus",
242 "pll1_sys",
243 "pll5_video_div",
244 "dummy",
245 "axi",
246 "enfc",
247 "ipu1_di0",
248 "ipu1_di1",
249 "ipu2_di0",
250 "ipu2_di1",
251 "ahb",
252 "ipg",
253 "ipg_per",
254 "ckil",
255 "pll4_audio_div"
256 };
257
258 static const char *cko2_p[] = {
259 "mmdc_ch0_axi",
260 "mmdc_ch1_axi",
261 "usdhc4",
262 "usdhc1",
263 "gpu2d_axi",
264 "dummy",
265 "ecspi_root",
266 "gpu3d_axi",
267 "usdhc3",
268 "dummy",
269 "arm",
270 "ipu1",
271 "ipu2",
272 "vdo_axi",
273 "osc",
274 "gpu2d_core",
275 "gpu3d_core",
276 "usdhc2",
277 "ssi1",
278 "ssi2",
279 "ssi3",
280 "gpu3d_shader",
281 "vpu_axi",
282 "can_root",
283 "ldb_di0",
284 "ldb_di1",
285 "esai_extal",
286 "eim_slow",
287 "uart_serial",
288 "spdif",
289 "asrc",
290 "hsi_tx"
291 };
292
293 static const char *cko_p[] = {
294 "cko1",
295 "cko2"
296 };
297
298 static const char *hsi_tx_p[] = {
299 "pll3_120m",
300 "pll2_pfd2_396m"
301 };
302
303 static const char *pcie_axi_p[] = {
304 "axi",
305 "ahb"
306 };
307
308 static const char *ssi_p[] = {
309 "pll3_pfd2_508m",
310 "pll3_pfd3_454m",
311 "pll4_audio_div"
312 };
313
314 static const char *usdhc_p[] = {
315 "pll2_pfd2_396m",
316 "pll2_pfd0_352m"
317 };
318
319 static const char *eim_p[] = {
320 "pll2_pfd2_396m",
321 "pll3_usb_otg",
322 "axi",
323 "pll2_pfd0_352m"
324 };
325
326 static const char *eim_slow_p[] = {
327 "axi",
328 "pll3_usb_otg",
329 "pll2_pfd2_396m",
330 "pll2_pfd0_352m"
331 };
332
333 static const char *enfc_p[] = {
334 "pll2_pfd0_352m",
335 "pll2_bus",
336 "pll3_usb_otg",
337 "pll2_pfd2_396m"
338 };
339
340 static const char *lvds_p[] = {
341 "dummy",
342 "dummy",
343 "dummy",
344 "dummy",
345 "dummy",
346 "dummy",
347 "pll4_audio",
348 "pll5_video",
349 "pll8_mlb",
350 "enet_ref",
351 "pcie_ref_125m",
352 "sata_ref_100m"
353 };
354
355 /* DT clock ID to clock name mappings */
356 static struct imx_clock_id {
357 u_int id;
358 const char *name;
359 } imx6_clock_ids[] = {
360 { IMX6CLK_DUMMY, "dummy" },
361 { IMX6CLK_CKIL, "ckil" },
362 { IMX6CLK_CKIH, "ckih" },
363 { IMX6CLK_OSC, "osc" },
364 { IMX6CLK_PLL2_PFD0_352M, "pll2_pfd0_352m" },
365 { IMX6CLK_PLL2_PFD1_594M, "pll2_pfd1_594m" },
366 { IMX6CLK_PLL2_PFD2_396M, "pll2_pfd2_396m" },
367 { IMX6CLK_PLL3_PFD0_720M, "pll3_pfd0_720m" },
368 { IMX6CLK_PLL3_PFD1_540M, "pll3_pfd1_540m" },
369 { IMX6CLK_PLL3_PFD2_508M, "pll3_pfd2_508m" },
370 { IMX6CLK_PLL3_PFD3_454M, "pll3_pfd3_454m" },
371 { IMX6CLK_PLL2_198M, "pll2_198m" },
372 { IMX6CLK_PLL3_120M, "pll3_120m" },
373 { IMX6CLK_PLL3_80M, "pll3_80m" },
374 { IMX6CLK_PLL3_60M, "pll3_60m" },
375 { IMX6CLK_TWD, "twd" },
376 { IMX6CLK_STEP, "step" },
377 { IMX6CLK_PLL1_SW, "pll1_sw" },
378 { IMX6CLK_PERIPH_PRE, "periph_pre" },
379 { IMX6CLK_PERIPH2_PRE, "periph2_pre" },
380 { IMX6CLK_PERIPH_CLK2_SEL, "periph_clk2_sel" },
381 { IMX6CLK_PERIPH2_CLK2_SEL, "periph2_clk2_sel" },
382 { IMX6CLK_AXI_SEL, "axi_sel" },
383 { IMX6CLK_ESAI_SEL, "esai_sel" },
384 { IMX6CLK_ASRC_SEL, "asrc_sel" },
385 { IMX6CLK_SPDIF_SEL, "spdif_sel" },
386 { IMX6CLK_GPU2D_AXI, "gpu2d_axi" },
387 { IMX6CLK_GPU3D_AXI, "gpu3d_axi" },
388 { IMX6CLK_GPU2D_CORE_SEL, "gpu2d_core_sel" },
389 { IMX6CLK_GPU3D_CORE_SEL, "gpu3d_core_sel" },
390 { IMX6CLK_GPU3D_SHADER_SEL, "gpu3d_shader_sel" },
391 { IMX6CLK_IPU1_SEL, "ipu1_sel" },
392 { IMX6CLK_IPU2_SEL, "ipu2_sel" },
393 { IMX6CLK_LDB_DI0_SEL, "ldb_di0_sel" },
394 { IMX6CLK_LDB_DI1_SEL, "ldb_di1_sel" },
395 { IMX6CLK_IPU1_DI0_PRE_SEL, "ipu1_di0_pre_sel" },
396 { IMX6CLK_IPU1_DI1_PRE_SEL, "ipu1_di1_pre_sel" },
397 { IMX6CLK_IPU2_DI0_PRE_SEL, "ipu2_di0_pre_sel" },
398 { IMX6CLK_IPU2_DI1_PRE_SEL, "ipu2_di1_pre_sel" },
399 { IMX6CLK_IPU1_DI0_SEL, "ipu1_di0_sel" },
400 { IMX6CLK_IPU1_DI1_SEL, "ipu1_di1_sel" },
401 { IMX6CLK_IPU2_DI0_SEL, "ipu2_di0_sel" },
402 { IMX6CLK_IPU2_DI1_SEL, "ipu2_di1_sel" },
403 { IMX6CLK_HSI_TX_SEL, "hsi_tx_sel" },
404 { IMX6CLK_PCIE_AXI_SEL, "pcie_axi_sel" },
405 { IMX6CLK_SSI1_SEL, "ssi1_sel" },
406 { IMX6CLK_SSI2_SEL, "ssi2_sel" },
407 { IMX6CLK_SSI3_SEL, "ssi3_sel" },
408 { IMX6CLK_USDHC1_SEL, "usdhc1_sel" },
409 { IMX6CLK_USDHC2_SEL, "usdhc2_sel" },
410 { IMX6CLK_USDHC3_SEL, "usdhc3_sel" },
411 { IMX6CLK_USDHC4_SEL, "usdhc4_sel" },
412 { IMX6CLK_ENFC_SEL, "enfc_sel" },
413 { IMX6CLK_EIM_SEL, "eim_sel" },
414 { IMX6CLK_EIM_SLOW_SEL, "eim_slow_sel" },
415 { IMX6CLK_VDO_AXI_SEL, "vdo_axi_sel" },
416 { IMX6CLK_VPU_AXI_SEL, "vpu_axi_sel" },
417 { IMX6CLK_CKO1_SEL, "cko1_sel" },
418 { IMX6CLK_PERIPH, "periph" },
419 { IMX6CLK_PERIPH2, "periph2" },
420 { IMX6CLK_PERIPH_CLK2, "periph_clk2" },
421 { IMX6CLK_PERIPH2_CLK2, "periph2_clk2" },
422 { IMX6CLK_IPG, "ipg" },
423 { IMX6CLK_IPG_PER, "ipg_per" },
424 { IMX6CLK_ESAI_PRED, "esai_pred" },
425 { IMX6CLK_ESAI_PODF, "esai_podf" },
426 { IMX6CLK_ASRC_PRED, "asrc_pred" },
427 { IMX6CLK_ASRC_PODF, "asrc_podf" },
428 { IMX6CLK_SPDIF_PRED, "spdif_pred" },
429 { IMX6CLK_SPDIF_PODF, "spdif_podf" },
430 { IMX6CLK_CAN_ROOT, "can_root" },
431 { IMX6CLK_ECSPI_ROOT, "ecspi_root" },
432 { IMX6CLK_GPU2D_CORE_PODF, "gpu2d_core_podf" },
433 { IMX6CLK_GPU3D_CORE_PODF, "gpu3d_core_podf" },
434 { IMX6CLK_GPU3D_SHADER, "gpu3d_shader" },
435 { IMX6CLK_IPU1_PODF, "ipu1_podf" },
436 { IMX6CLK_IPU2_PODF, "ipu2_podf" },
437 { IMX6CLK_LDB_DI0_PODF, "ldb_di0_podf" },
438 { IMX6CLK_LDB_DI1_PODF, "ldb_di1_podf" },
439 { IMX6CLK_IPU1_DI0_PRE, "ipu1_di0_pre" },
440 { IMX6CLK_IPU1_DI1_PRE, "ipu1_di1_pre" },
441 { IMX6CLK_IPU2_DI0_PRE, "ipu2_di0_pre" },
442 { IMX6CLK_IPU2_DI1_PRE, "ipu2_di1_pre" },
443 { IMX6CLK_HSI_TX_PODF, "hsi_tx_podf" },
444 { IMX6CLK_SSI1_PRED, "ssi1_pred" },
445 { IMX6CLK_SSI1_PODF, "ssi1_podf" },
446 { IMX6CLK_SSI2_PRED, "ssi2_pred" },
447 { IMX6CLK_SSI2_PODF, "ssi2_podf" },
448 { IMX6CLK_SSI3_PRED, "ssi3_pred" },
449 { IMX6CLK_SSI3_PODF, "ssi3_podf" },
450 { IMX6CLK_UART_SERIAL_PODF, "uart_serial_podf" },
451 { IMX6CLK_USDHC1_PODF, "usdhc1_podf" },
452 { IMX6CLK_USDHC2_PODF, "usdhc2_podf" },
453 { IMX6CLK_USDHC3_PODF, "usdhc3_podf" },
454 { IMX6CLK_USDHC4_PODF, "usdhc4_podf" },
455 { IMX6CLK_ENFC_PRED, "enfc_pred" },
456 { IMX6CLK_ENFC_PODF, "enfc_podf" },
457 { IMX6CLK_EIM_PODF, "eim_podf" },
458 { IMX6CLK_EIM_SLOW_PODF, "eim_slow_podf" },
459 { IMX6CLK_VPU_AXI_PODF, "vpu_axi_podf" },
460 { IMX6CLK_CKO1_PODF, "cko1_podf" },
461 { IMX6CLK_AXI, "axi" },
462 { IMX6CLK_MMDC_CH0_AXI_PODF, "mmdc_ch0_axi_podf" },
463 { IMX6CLK_MMDC_CH1_AXI_PODF, "mmdc_ch1_axi_podf" },
464 { IMX6CLK_ARM, "arm" },
465 { IMX6CLK_AHB, "ahb" },
466 { IMX6CLK_APBH_DMA, "apbh_dma" },
467 { IMX6CLK_ASRC, "asrc" },
468 { IMX6CLK_CAN1_IPG, "can1_ipg" },
469 { IMX6CLK_CAN1_SERIAL, "can1_serial" },
470 { IMX6CLK_CAN2_IPG, "can2_ipg" },
471 { IMX6CLK_CAN2_SERIAL, "can2_serial" },
472 { IMX6CLK_ECSPI1, "ecspi1" },
473 { IMX6CLK_ECSPI2, "ecspi2" },
474 { IMX6CLK_ECSPI3, "ecspi3" },
475 { IMX6CLK_ECSPI4, "ecspi4" },
476 { IMX6CLK_ECSPI5, "ecspi5" },
477 { IMX6CLK_ENET, "enet" },
478 { IMX6CLK_ESAI_EXTAL, "esai_extal" },
479 { IMX6CLK_GPT_IPG, "gpt_ipg" },
480 { IMX6CLK_GPT_IPG_PER, "gpt_ipg_per" },
481 { IMX6CLK_GPU2D_CORE, "gpu2d_core" },
482 { IMX6CLK_GPU3D_CORE, "gpu3d_core" },
483 { IMX6CLK_HDMI_IAHB, "hdmi_iahb" },
484 { IMX6CLK_HDMI_ISFR, "hdmi_isfr" },
485 { IMX6CLK_I2C1, "i2c1" },
486 { IMX6CLK_I2C2, "i2c2" },
487 { IMX6CLK_I2C3, "i2c3" },
488 { IMX6CLK_IIM, "iim" },
489 { IMX6CLK_ENFC, "enfc" },
490 { IMX6CLK_IPU1, "ipu1" },
491 { IMX6CLK_IPU1_DI0, "ipu1_di0" },
492 { IMX6CLK_IPU1_DI1, "ipu1_di1" },
493 { IMX6CLK_IPU2, "ipu2" },
494 { IMX6CLK_IPU2_DI0, "ipu2_di0" },
495 { IMX6CLK_LDB_DI0, "ldb_di0" },
496 { IMX6CLK_LDB_DI1, "ldb_di1" },
497 { IMX6CLK_IPU2_DI1, "ipu2_di1" },
498 { IMX6CLK_HSI_TX, "hsi_tx" },
499 { IMX6CLK_MLB, "mlb" },
500 { IMX6CLK_MMDC_CH0_AXI, "mmdc_ch0_axi" },
501 { IMX6CLK_MMDC_CH1_AXI, "mmdc_ch1_axi" },
502 { IMX6CLK_OCRAM, "ocram" },
503 { IMX6CLK_OPENVG_AXI, "openvg_axi" },
504 { IMX6CLK_PCIE_AXI, "pcie_axi" },
505 { IMX6CLK_PWM1, "pwm1" },
506 { IMX6CLK_PWM2, "pwm2" },
507 { IMX6CLK_PWM3, "pwm3" },
508 { IMX6CLK_PWM4, "pwm4" },
509 { IMX6CLK_PER1_BCH, "per1_bch" },
510 { IMX6CLK_GPMI_BCH_APB, "gpmi_bch_apb" },
511 { IMX6CLK_GPMI_BCH, "gpmi_bch" },
512 { IMX6CLK_GPMI_IO, "gpmi_io" },
513 { IMX6CLK_GPMI_APB, "gpmi_apb" },
514 { IMX6CLK_SATA, "sata" },
515 { IMX6CLK_SDMA, "sdma" },
516 { IMX6CLK_SPBA, "spba" },
517 { IMX6CLK_SSI1, "ssi1" },
518 { IMX6CLK_SSI2, "ssi2" },
519 { IMX6CLK_SSI3, "ssi3" },
520 { IMX6CLK_UART_IPG, "uart_ipg" },
521 { IMX6CLK_UART_SERIAL, "uart_serial" },
522 { IMX6CLK_USBOH3, "usboh3" },
523 { IMX6CLK_USDHC1, "usdhc1" },
524 { IMX6CLK_USDHC2, "usdhc2" },
525 { IMX6CLK_USDHC3, "usdhc3" },
526 { IMX6CLK_USDHC4, "usdhc4" },
527 { IMX6CLK_VDO_AXI, "vdo_axi" },
528 { IMX6CLK_VPU_AXI, "vpu_axi" },
529 { IMX6CLK_CKO1, "cko1" },
530 { IMX6CLK_PLL1_SYS, "pll1_sys" },
531 { IMX6CLK_PLL2_BUS, "pll2_bus" },
532 { IMX6CLK_PLL3_USB_OTG, "pll3_usb_otg" },
533 { IMX6CLK_PLL4_AUDIO, "pll4_audio" },
534 { IMX6CLK_PLL5_VIDEO, "pll5_video" },
535 { IMX6CLK_PLL8_MLB, "pll8_mlb" },
536 { IMX6CLK_PLL7_USB_HOST, "pll7_usb_host" },
537 { IMX6CLK_PLL6_ENET, "pll6_enet" },
538 { IMX6CLK_SSI1_IPG, "ssi1_ipg" },
539 { IMX6CLK_SSI2_IPG, "ssi2_ipg" },
540 { IMX6CLK_SSI3_IPG, "ssi3_ipg" },
541 { IMX6CLK_ROM, "rom" },
542 { IMX6CLK_USBPHY1, "usbphy1" },
543 { IMX6CLK_USBPHY2, "usbphy2" },
544 { IMX6CLK_LDB_DI0_DIV_3_5, "ldb_di0_div_3_5" },
545 { IMX6CLK_LDB_DI1_DIV_3_5, "ldb_di1_div_3_5" },
546 { IMX6CLK_SATA_REF, "sata_ref" },
547 { IMX6CLK_SATA_REF_100M, "sata_ref_100m" },
548 { IMX6CLK_PCIE_REF, "pcie_ref" },
549 { IMX6CLK_PCIE_REF_125M, "pcie_ref_125m" },
550 { IMX6CLK_ENET_REF, "enet_ref" },
551 { IMX6CLK_USBPHY1_GATE, "usbphy1_gate" },
552 { IMX6CLK_USBPHY2_GATE, "usbphy2_gate" },
553 { IMX6CLK_PLL4_POST_DIV, "pll4_post_div" },
554 { IMX6CLK_PLL5_POST_DIV, "pll5_post_div" },
555 { IMX6CLK_PLL5_VIDEO_DIV, "pll5_video_div" },
556 { IMX6CLK_EIM_SLOW, "eim_slow" },
557 { IMX6CLK_SPDIF, "spdif" },
558 { IMX6CLK_CKO2_SEL, "cko2_sel" },
559 { IMX6CLK_CKO2_PODF, "cko2_podf" },
560 { IMX6CLK_CKO2, "cko2" },
561 { IMX6CLK_CKO, "cko" },
562 { IMX6CLK_VDOA, "vdoa" },
563 { IMX6CLK_PLL4_AUDIO_DIV, "pll4_audio_div" },
564 { IMX6CLK_LVDS1_SEL, "lvds1_sel" },
565 { IMX6CLK_LVDS2_SEL, "lvds2_sel" },
566 { IMX6CLK_LVDS1_GATE, "lvds1_gate" },
567 { IMX6CLK_LVDS2_GATE, "lvds2_gate" },
568 { IMX6CLK_ESAI_IPG, "esai_ipg" },
569 { IMX6CLK_ESAI_MEM, "esai_mem" },
570 { IMX6CLK_ASRC_IPG, "asrc_ipg" },
571 { IMX6CLK_ASRC_MEM, "asrc_mem" },
572 { IMX6CLK_LVDS1_IN, "lvds1_in" },
573 { IMX6CLK_LVDS2_IN, "lvds2_in" },
574 { IMX6CLK_ANACLK1, "anaclk1" },
575 { IMX6CLK_ANACLK2, "anaclk2" },
576 { IMX6CLK_PLL1_BYPASS_SRC, "pll1_bypass_src" },
577 { IMX6CLK_PLL2_BYPASS_SRC, "pll2_bypass_src" },
578 { IMX6CLK_PLL3_BYPASS_SRC, "pll3_bypass_src" },
579 { IMX6CLK_PLL4_BYPASS_SRC, "pll4_bypass_src" },
580 { IMX6CLK_PLL5_BYPASS_SRC, "pll5_bypass_src" },
581 { IMX6CLK_PLL6_BYPASS_SRC, "pll6_bypass_src" },
582 { IMX6CLK_PLL7_BYPASS_SRC, "pll7_bypass_src" },
583 { IMX6CLK_PLL1, "pll1" },
584 { IMX6CLK_PLL2, "pll2" },
585 { IMX6CLK_PLL3, "pll3" },
586 { IMX6CLK_PLL4, "pll4" },
587 { IMX6CLK_PLL5, "pll5" },
588 { IMX6CLK_PLL6, "pll6" },
589 { IMX6CLK_PLL7, "pll7" },
590 { IMX6CLK_PLL1_BYPASS, "pll1_bypass" },
591 { IMX6CLK_PLL2_BYPASS, "pll2_bypass" },
592 { IMX6CLK_PLL3_BYPASS, "pll3_bypass" },
593 { IMX6CLK_PLL4_BYPASS, "pll4_bypass" },
594 { IMX6CLK_PLL5_BYPASS, "pll5_bypass" },
595 { IMX6CLK_PLL6_BYPASS, "pll6_bypass" },
596 { IMX6CLK_PLL7_BYPASS, "pll7_bypass" },
597 { IMX6CLK_GPT_3M, "gpt_3m" },
598 { IMX6CLK_VIDEO_27M, "video_27m" },
599 { IMX6CLK_MIPI_CORE_CFG, "mipi_core_cfg" },
600 { IMX6CLK_MIPI_IPG, "mipi_ipg" },
601 { IMX6CLK_CAAM_MEM, "caam_mem" },
602 { IMX6CLK_CAAM_ACLK, "caam_aclk" },
603 { IMX6CLK_CAAM_IPG, "caam_ipg" },
604 { IMX6CLK_SPDIF_GCLK, "spdif_gclk" },
605 { IMX6CLK_UART_SEL, "uart_sel" },
606 { IMX6CLK_IPG_PER_SEL, "ipg_per_sel" },
607 { IMX6CLK_ECSPI_SEL, "ecspi_sel" },
608 { IMX6CLK_CAN_SEL, "can_sel" },
609 { IMX6CLK_MMDC_CH1_AXI_CG, "mmdc_ch1_axi_cg" },
610 { IMX6CLK_PRE0, "pre0" },
611 { IMX6CLK_PRE1, "pre1" },
612 { IMX6CLK_PRE2, "pre2" },
613 { IMX6CLK_PRE3, "pre3" },
614 { IMX6CLK_PRG0_AXI, "prg0_axi" },
615 { IMX6CLK_PRG1_AXI, "prg1_axi" },
616 { IMX6CLK_PRG0_APB, "prg0_apb" },
617 { IMX6CLK_PRG1_APB, "prg1_apb" },
618 { IMX6CLK_PRE_AXI, "pre_axi" },
619 { IMX6CLK_MLB_SEL, "mlb_sel" },
620 { IMX6CLK_MLB_PODF, "mlb_podf" },
621 { IMX6CLK_END, "end" },
622 };
623
624 /* Clock Divider Tables */
625 static const int enet_ref_tbl[] = { 20, 10, 5, 4, 0 };
626 static const int post_div_tbl[] = { 4, 2, 1, 0 };
627 static const int audiovideo_div_tbl[] = { 1, 2, 1, 4, 0 };
628
629 static struct imx6_clk imx6_clks[] = {
630 CLK_FIXED("dummy", 0),
631
632 CLK_FIXED("ckil", IMX6_CKIL_FREQ),
633 CLK_FIXED("ckih", IMX6_CKIH_FREQ),
634 CLK_FIXED("osc", IMX6_OSC_FREQ),
635 CLK_FIXED("anaclk1", IMX6_ANACLK1_FREQ),
636 CLK_FIXED("anaclk2", IMX6_ANACLK2_FREQ),
637
638 CLK_FIXED_FACTOR("sata_ref", "pll6_enet", 5, 1),
639 CLK_FIXED_FACTOR("pcie_ref", "pll6_enet", 4, 1),
640 CLK_FIXED_FACTOR("pll2_198m", "pll2_pfd2_396m", 2, 1),
641 CLK_FIXED_FACTOR("pll3_120m", "pll3_usb_otg", 4, 1),
642 CLK_FIXED_FACTOR("pll3_80m", "pll3_usb_otg", 6, 1),
643 CLK_FIXED_FACTOR("pll3_60m", "pll3_usb_otg", 8, 1),
644 CLK_FIXED_FACTOR("twd", "arm", 2, 1),
645 CLK_FIXED_FACTOR("gpt_3m", "osc", 8, 1),
646 CLK_FIXED_FACTOR("video_27m", "pll3_pfd1_540m", 20, 1),
647 CLK_FIXED_FACTOR("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1),
648 CLK_FIXED_FACTOR("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1),
649 CLK_FIXED_FACTOR("ldb_di0_div_3_5", "ldb_di0_sel", 7, 2),
650 CLK_FIXED_FACTOR("ldb_di1_div_3_5", "ldb_di1_sel", 7, 2),
651
652 CLK_PFD("pll2_pfd0_352m", "pll2_bus", PFD_528, 0),
653 CLK_PFD("pll2_pfd1_594m", "pll2_bus", PFD_528, 1),
654 CLK_PFD("pll2_pfd2_396m", "pll2_bus", PFD_528, 2),
655 CLK_PFD("pll3_pfd0_720m", "pll3_usb_otg", PFD_480, 0),
656 CLK_PFD("pll3_pfd1_540m", "pll3_usb_otg", PFD_480, 1),
657 CLK_PFD("pll3_pfd2_508m", "pll3_usb_otg", PFD_480, 2),
658 CLK_PFD("pll3_pfd3_454m", "pll3_usb_otg", PFD_480, 3),
659
660 CLK_PLL("pll1", "osc", SYS, PLL_ARM, DIV_SELECT, POWERDOWN, 0),
661 CLK_PLL("pll2", "osc", GENERIC, PLL_SYS, DIV_SELECT, POWERDOWN, 0),
662 CLK_PLL("pll3", "osc", USB, PLL_USB1, DIV_SELECT, POWER, 0),
663 CLK_PLL("pll4", "osc", AUDIO_VIDEO, PLL_AUDIO, DIV_SELECT, POWERDOWN, 0),
664 CLK_PLL("pll5", "osc", AUDIO_VIDEO, PLL_VIDEO, DIV_SELECT, POWERDOWN, 0),
665 CLK_PLL("pll6", "osc", ENET, PLL_ENET, DIV_SELECT, POWERDOWN, 500000000),
666 CLK_PLL("pll7", "osc", USB, PLL_USB2, DIV_SELECT, POWER, 0),
667
668 CLK_DIV("periph_clk2", "periph_clk2_sel", CBCDR, PERIPH_CLK2_PODF),
669 CLK_DIV("periph2_clk2", "periph2_clk2_sel", CBCDR, PERIPH2_CLK2_PODF),
670 CLK_DIV("ipg", "ahb", CBCDR, IPG_PODF),
671 CLK_DIV("esai_pred", "esai_sel", CS1CDR, ESAI_CLK_PRED),
672 CLK_DIV("esai_podf", "esai_pred", CS1CDR, ESAI_CLK_PODF),
673 CLK_DIV("asrc_pred", "asrc_sel", CDCDR, SPDIF1_CLK_PRED),
674 CLK_DIV("asrc_podf", "asrc_pred", CDCDR, SPDIF1_CLK_PODF),
675 CLK_DIV("spdif_pred", "spdif_sel", CDCDR, SPDIF0_CLK_PRED),
676 CLK_DIV("spdif_podf", "spdif_pred", CDCDR, SPDIF0_CLK_PODF),
677 CLK_DIV("ecspi_root", "pll3_60m", CSCDR2, ECSPI_CLK_PODF),
678 CLK_DIV("can_root", "pll3_60m", CSCMR2, CAN_CLK_PODF),
679 CLK_DIV("uart_serial_podf", "pll3_80m", CSCDR1, UART_CLK_PODF),
680 CLK_DIV("gpu2d_core_podf", "gpu2d_core_sel", CBCMR, GPU2D_CORE_CLK_PODF),
681 CLK_DIV("gpu3d_core_podf", "gpu3d_core_sel", CBCMR, GPU3D_CORE_PODF),
682 CLK_DIV("gpu3d_shader", "gpu3d_shader_sel", CBCMR, GPU3D_SHADER_PODF),
683 CLK_DIV("ipu1_podf", "ipu1_sel", CSCDR3, IPU1_HSP_PODF),
684 CLK_DIV("ipu2_podf", "ipu2_sel", CSCDR3, IPU2_HSP_PODF),
685 CLK_DIV("ldb_di0_podf", "ldb_di0_div_3_5", CSCMR2, LDB_DI0_IPU_DIV),
686 CLK_DIV("ldb_di1_podf", "ldb_di1_div_3_5", CSCMR2, LDB_DI1_IPU_DIV),
687 CLK_DIV("ipu1_di0_pre", "ipu1_di0_pre_sel", CHSCCDR, IPU1_DI0_PODF),
688 CLK_DIV("ipu1_di1_pre", "ipu1_di1_pre_sel", CHSCCDR, IPU1_DI1_PODF),
689 CLK_DIV("ipu2_di0_pre", "ipu2_di0_pre_sel", CSCDR2, IPU2_DI0_PODF),
690 CLK_DIV("ipu2_di1_pre", "ipu2_di1_pre_sel", CSCDR2, IPU2_DI1_PODF),
691 CLK_DIV("hsi_tx_podf", "hsi_tx_sel", CDCDR, HSI_TX_PODF),
692 CLK_DIV("ssi1_pred", "ssi1_sel", CS1CDR, SSI1_CLK_PRED),
693 CLK_DIV("ssi1_podf", "ssi1_pred", CS1CDR, SSI1_CLK_PODF),
694 CLK_DIV("ssi2_pred", "ssi2_sel", CS2CDR, SSI2_CLK_PRED),
695 CLK_DIV("ssi2_podf", "ssi2_pred", CS2CDR, SSI2_CLK_PODF),
696 CLK_DIV("ssi3_pred", "ssi3_sel", CS1CDR, SSI3_CLK_PRED),
697 CLK_DIV("ssi3_podf", "ssi3_pred", CS1CDR, SSI3_CLK_PODF),
698 CLK_DIV("usdhc1_podf", "usdhc1_sel", CSCDR1, USDHC1_PODF),
699 CLK_DIV("usdhc2_podf", "usdhc2_sel", CSCDR1, USDHC2_PODF),
700 CLK_DIV("usdhc3_podf", "usdhc3_sel", CSCDR1, USDHC3_PODF),
701 CLK_DIV("usdhc4_podf", "usdhc4_sel", CSCDR1, USDHC4_PODF),
702 CLK_DIV("enfc_pred", "enfc_sel", CS2CDR, ENFC_CLK_PRED),
703 CLK_DIV("enfc_podf", "enfc_pred", CS2CDR, ENFC_CLK_PODF),
704 CLK_DIV("vpu_axi_podf", "vpu_axi_sel", CSCDR1, VPU_AXI_PODF),
705 CLK_DIV("cko1_podf", "cko1_sel", CCOSR, CLKO1_DIV),
706 CLK_DIV("cko2_podf", "cko2_sel", CCOSR, CLKO2_DIV),
707 CLK_DIV("ipg_per", "ipg", CSCMR1, PERCLK_PODF),
708 CLK_DIV("eim_podf", "eim_sel", CSCMR1, ACLK_PODF),
709 CLK_DIV("eim_slow_podf", "eim_slow_sel", CSCMR1, ACLK_EIM_SLOW_PODF),
710
711 CLK_DIV_BUSY("axi", "axi_sel", CBCDR, AXI_PODF, CDHIPR, AXI_PODF_BUSY),
712 CLK_DIV_BUSY("mmdc_ch0_axi_podf", "periph", CBCDR, MMDC_CH0_AXI_PODF, CDHIPR, MMDC_CH0_PODF_BUSY),
713 CLK_DIV_BUSY("mmdc_ch1_axi_podf", "periph2", CBCDR, MMDC_CH1_AXI_PODF, CDHIPR, MMDC_CH1_PODF_BUSY),
714 CLK_DIV_BUSY("arm", "pll1_sw", CACRR, ARM_PODF, CDHIPR, ARM_PODF_BUSY),
715 CLK_DIV_BUSY("ahb", "periph", CBCDR, AHB_PODF, CDHIPR, AHB_PODF_BUSY),
716
717 CLK_DIV_TABLE("pll4_post_div", "pll4_audio", PLL_AUDIO, POST_DIV_SELECT, post_div_tbl),
718 CLK_DIV_TABLE("pll4_audio_div", "pll4_post_div", MISC2, AUDIO_DIV_LSB, audiovideo_div_tbl),
719 CLK_DIV_TABLE("pll5_post_div", "pll5_video", PLL_VIDEO, POST_DIV_SELECT, post_div_tbl),
720 CLK_DIV_TABLE("pll5_video_div", "pll5_post_div", MISC2, VIDEO_DIV, audiovideo_div_tbl),
721 CLK_DIV_TABLE("enet_ref", "pll6_enet", PLL_ENET, DIV_SELECT, enet_ref_tbl),
722
723 CLK_MUX("step", step_p, CCM, CCSR, STEP_SEL),
724 CLK_MUX("pll1_sw", pll1_sw_p, CCM, CCSR, PLL1_SW_CLK_SEL),
725 CLK_MUX("periph_pre", periph_pre_p, CCM, CBCMR, PRE_PERIPH_CLK_SEL),
726 CLK_MUX("periph2_pre", periph_pre_p, CCM, CBCMR, PRE_PERIPH2_CLK_SEL),
727 CLK_MUX("periph_clk2_sel", periph_clk2_p, CCM,CBCMR, PERIPH_CLK2_SEL),
728 CLK_MUX("periph2_clk2_sel", periph2_clk2_p, CCM,CBCMR, PERIPH2_CLK2_SEL),
729 CLK_MUX("axi_sel", axi_p, CCM, CBCDR, AXI_SEL),
730 CLK_MUX("asrc_sel", audio_p, CCM, CDCDR, SPDIF1_CLK_SEL),
731 CLK_MUX("spdif_sel", audio_p, CCM, CDCDR, SPDIF0_CLK_SEL),
732 CLK_MUX("gpu2d_core_sel", gpu2d_core_p, CCM, CBCMR, GPU2D_CLK_SEL),
733 CLK_MUX("gpu3d_core_sel", gpu3d_core_p, CCM, CBCMR, GPU3D_CORE_CLK_SEL),
734 CLK_MUX("gpu3d_shader_sel", gpu3d_shader_p, CCM,CBCMR, GPU3D_SHADER_CLK_SEL),
735 CLK_MUX("esai_sel", audio_p, CCM, CSCMR2, ESAI_CLK_SEL),
736 CLK_MUX("ipu1_sel", ipu_p, CCM, CSCDR3, IPU1_HSP_CLK_SEL),
737 CLK_MUX("ipu2_sel", ipu_p, CCM, CSCDR3, IPU2_HSP_CLK_SEL),
738 CLK_MUX("ipu1_di0_pre_sel", ipu_di_pre_p, CCM, CHSCCDR, IPU1_DI0_PRE_CLK_SEL),
739 CLK_MUX("ipu1_di1_pre_sel", ipu_di_pre_p, CCM, CHSCCDR, IPU1_DI1_PRE_CLK_SEL),
740 CLK_MUX("ipu2_di0_pre_sel", ipu_di_pre_p, CCM, CSCDR2, IPU2_DI0_PRE_CLK_SEL),
741 CLK_MUX("ipu2_di1_pre_sel", ipu_di_pre_p, CCM, CSCDR2, IPU2_DI1_PRE_CLK_SEL),
742 CLK_MUX("ipu1_di0_sel", ipu1_di0_p, CCM, CHSCCDR, IPU1_DI0_CLK_SEL),
743 CLK_MUX("ipu1_di1_sel", ipu1_di1_p, CCM, CHSCCDR, IPU1_DI1_CLK_SEL),
744 CLK_MUX("ipu2_di0_sel", ipu2_di0_p, CCM, CSCDR2, IPU2_DI0_CLK_SEL),
745 CLK_MUX("ipu2_di1_sel", ipu2_di1_p, CCM, CSCDR2, IPU2_DI1_CLK_SEL),
746 CLK_MUX("ldb_di0_sel", ldb_di_p, CCM, CS2CDR, LDB_DI0_CLK_SEL),
747 CLK_MUX("ldb_di1_sel", ldb_di_p, CCM, CS2CDR, LDB_DI1_CLK_SEL),
748 CLK_MUX("vdo_axi_sel", vdo_axi_p, CCM, CBCMR, VDOAXI_CLK_SEL),
749 CLK_MUX("vpu_axi_sel", vpu_axi_p, CCM, CBCMR, VPU_AXI_CLK_SEL),
750 CLK_MUX("cko1_sel", cko1_p, CCM, CCOSR, CLKO1_SEL),
751 CLK_MUX("cko2_sel", cko2_p, CCM, CCOSR, CLKO2_SEL),
752 CLK_MUX("cko", cko_p, CCM, CCOSR, CLK_OUT_SEL),
753 CLK_MUX("hsi_tx_sel", hsi_tx_p, CCM, CDCDR, HSI_TX_CLK_SEL),
754 CLK_MUX("pcie_axi_sel", pcie_axi_p, CCM, CBCMR, PCIE_AXI_CLK_SEL),
755 CLK_MUX("ssi1_sel", ssi_p, CCM, CSCMR1, SSI1_CLK_SEL),
756 CLK_MUX("ssi2_sel", ssi_p, CCM, CSCMR1, SSI2_CLK_SEL),
757 CLK_MUX("ssi3_sel", ssi_p, CCM, CSCMR1, SSI3_CLK_SEL),
758 CLK_MUX("usdhc1_sel", usdhc_p, CCM, CSCMR1, USDHC1_CLK_SEL),
759 CLK_MUX("usdhc2_sel", usdhc_p, CCM, CSCMR1, USDHC2_CLK_SEL),
760 CLK_MUX("usdhc3_sel", usdhc_p, CCM, CSCMR1, USDHC3_CLK_SEL),
761 CLK_MUX("usdhc4_sel", usdhc_p, CCM, CSCMR1, USDHC4_CLK_SEL),
762 CLK_MUX("eim_sel", eim_p, CCM, CSCMR1, ACLK_SEL),
763 CLK_MUX("eim_slow_sel", eim_slow_p, CCM, CSCMR1, ACLK_EIM_SLOW_SEL),
764 CLK_MUX("enfc_sel", enfc_p, CCM, CS2CDR, ENFC_CLK_SEL),
765
766 CLK_MUX("pll1_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_ARM, BYPASS_CLK_SRC),
767 CLK_MUX("pll2_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_SYS, BYPASS_CLK_SRC),
768 CLK_MUX("pll3_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_USB1, BYPASS_CLK_SRC),
769 CLK_MUX("pll4_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_AUDIO, BYPASS_CLK_SRC),
770 CLK_MUX("pll5_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_VIDEO, BYPASS_CLK_SRC),
771 CLK_MUX("pll6_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_ENET, BYPASS_CLK_SRC),
772 CLK_MUX("pll7_bypass_src", pll_bypass_src_p, CCM_ANALOG, PLL_USB2, BYPASS_CLK_SRC),
773 CLK_MUX("pll1_bypass", pll1_bypass_p, CCM_ANALOG, PLL_ARM, BYPASS),
774 CLK_MUX("pll2_bypass", pll2_bypass_p, CCM_ANALOG, PLL_SYS, BYPASS),
775 CLK_MUX("pll3_bypass", pll3_bypass_p, CCM_ANALOG, PLL_USB1, BYPASS),
776 CLK_MUX("pll4_bypass", pll4_bypass_p, CCM_ANALOG, PLL_AUDIO, BYPASS),
777 CLK_MUX("pll5_bypass", pll5_bypass_p, CCM_ANALOG, PLL_VIDEO, BYPASS),
778 CLK_MUX("pll6_bypass", pll6_bypass_p, CCM_ANALOG, PLL_ENET, BYPASS),
779 CLK_MUX("pll7_bypass", pll7_bypass_p, CCM_ANALOG, PLL_USB2, BYPASS),
780
781 CLK_MUX("lvds1_sel", lvds_p, CCM_ANALOG, MISC1, LVDS_CLK1_SRC),
782 CLK_MUX("lvds2_sel", lvds_p, CCM_ANALOG, MISC1, LVDS_CLK2_SRC),
783
784 CLK_MUX_BUSY("periph", periph_p, CBCDR, PERIPH_CLK_SEL, CDHIPR, PERIPH_CLK_SEL_BUSY),
785 CLK_MUX_BUSY("periph2", periph2_p, CBCDR, PERIPH2_CLK_SEL, CDHIPR, PERIPH2_CLK_SEL_BUSY),
786
787 CLK_GATE("apbh_dma", "usdhc3", CCM, CCGR0, APBHDMA_HCLK_ENABLE),
788 CLK_GATE("asrc", "asrc_podf", CCM, CCGR0, ASRC_CLK_ENABLE),
789 CLK_GATE("asrc_ipg", "ahb", CCM, CCGR0, ASRC_CLK_ENABLE),
790 CLK_GATE("asrc_mem", "ahb", CCM, CCGR0, ASRC_CLK_ENABLE),
791 CLK_GATE("caam_mem", "ahb", CCM, CCGR0, CAAM_SECURE_MEM_CLK_ENABLE),
792 CLK_GATE("caam_aclk", "ahb", CCM, CCGR0, CAAM_WRAPPER_ACLK_ENABLE),
793 CLK_GATE("caam_ipg", "ipg", CCM, CCGR0, CAAM_WRAPPER_IPG_ENABLE),
794 CLK_GATE("can1_ipg", "ipg", CCM, CCGR0, CAN1_CLK_ENABLE),
795 CLK_GATE("can1_serial", "can_root", CCM, CCGR0, CAN1_SERIAL_CLK_ENABLE),
796 CLK_GATE("can2_ipg", "ipg", CCM, CCGR0, CAN2_CLK_ENABLE),
797 CLK_GATE("can2_serial", "can_root", CCM, CCGR0, CAN2_SERIAL_CLK_ENABLE),
798 CLK_GATE("ecspi1", "ecspi_root", CCM, CCGR1, ECSPI1_CLK_ENABLE),
799 CLK_GATE("ecspi2", "ecspi_root", CCM, CCGR1, ECSPI2_CLK_ENABLE),
800 CLK_GATE("ecspi3", "ecspi_root", CCM, CCGR1, ECSPI3_CLK_ENABLE),
801 CLK_GATE("ecspi4", "ecspi_root", CCM, CCGR1, ECSPI4_CLK_ENABLE),
802 CLK_GATE("ecspi5", "ecspi_root", CCM, CCGR1, ECSPI5_CLK_ENABLE),
803 CLK_GATE("enet", "ipg", CCM, CCGR1, ENET_CLK_ENABLE),
804 CLK_GATE("esai_extal", "esai_podf", CCM, CCGR1, ESAI_CLK_ENABLE),
805 CLK_GATE("esai_ipg", "ahb", CCM, CCGR1, ESAI_CLK_ENABLE),
806 CLK_GATE("esai_mem", "ahb", CCM, CCGR1, ESAI_CLK_ENABLE),
807 CLK_GATE("gpt_ipg", "ipg", CCM, CCGR1, GPT_CLK_ENABLE),
808 CLK_GATE("gpt_ipg_per", "ipg_per", CCM, CCGR1, GPT_SERIAL_CLK_ENABLE),
809 CLK_GATE("gpu2d_core", "gpu2d_core_podf", CCM, CCGR1, GPU2D_CLK_ENABLE),
810 CLK_GATE("gpu3d_core", "gpu3d_core_podf", CCM, CCGR1, GPU3D_CLK_ENABLE),
811 CLK_GATE("hdmi_iahb", "ahb", CCM, CCGR2, HDMI_TX_IAHBCLK_ENABLE),
812 CLK_GATE("hdmi_isfr", "video_27m", CCM, CCGR2, HDMI_TX_ISFRCLK_ENABLE),
813 CLK_GATE("i2c1", "ipg_per", CCM, CCGR2, I2C1_SERIAL_CLK_ENABLE),
814 CLK_GATE("i2c2", "ipg_per", CCM, CCGR2, I2C2_SERIAL_CLK_ENABLE),
815 CLK_GATE("i2c3", "ipg_per", CCM, CCGR2, I2C3_SERIAL_CLK_ENABLE),
816 CLK_GATE("iim", "ipg", CCM, CCGR2, IIM_CLK_ENABLE),
817 CLK_GATE("enfc", "enfc_podf", CCM, CCGR2, IOMUX_IPT_CLK_IO_CLK_ENABLE),
818 CLK_GATE("vdoa", "vdo_axi", CCM, CCGR2, IPSYNC_VDOA_IPG_CLK_ENABLE),
819 CLK_GATE("ipu1", "ipu1_podf", CCM, CCGR3, IPU1_IPU_CLK_ENABLE),
820 CLK_GATE("ipu1_di0", "ipu1_di0_sel", CCM, CCGR3, IPU1_IPU_DI0_CLK_ENABLE),
821 CLK_GATE("ipu1_di1", "ipu1_di1_sel", CCM, CCGR3, IPU1_IPU_DI1_CLK_ENABLE),
822 CLK_GATE("ipu2", "ipu2_podf", CCM, CCGR3, IPU2_IPU_CLK_ENABLE),
823 CLK_GATE("ipu2_di0", "ipu2_di0_sel", CCM, CCGR3, IPU2_IPU_DI0_CLK_ENABLE),
824 CLK_GATE("ldb_di0", "ldb_di0_podf", CCM, CCGR3, LDB_DI0_CLK_ENABLE),
825 CLK_GATE("ldb_di1", "ldb_di1_podf", CCM, CCGR3, LDB_DI1_CLK_ENABLE),
826 CLK_GATE("ipu2_di1", "ipu2_di1_sel", CCM, CCGR3, IPU2_IPU_DI1_CLK_ENABLE),
827 CLK_GATE("hsi_tx", "hsi_tx_podf", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE),
828 CLK_GATE("mipi_core_cfg", "video_27m", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE),
829 CLK_GATE("mipi_ipg", "ipg", CCM, CCGR3, MIPI_CORE_CFG_CLK_ENABLE),
830 CLK_GATE("mlb", "axi", CCM, CCGR3, MLB_CLK_ENABLE),
831 CLK_GATE("mmdc_ch0_axi", "mmdc_ch0_axi_podf", CCM, CCGR3, MMDC_CORE_ACLK_FAST_CORE_P0_ENABLE),
832 CLK_GATE("mmdc_ch1_axi", "mmdc_ch1_axi_podf", CCM, CCGR3, MMDC_CORE_ACLK_FAST_CORE_P1_ENABLE),
833 CLK_GATE("ocram", "ahb", CCM, CCGR3, OCRAM_CLK_ENABLE),
834 CLK_GATE("openvg_axi", "axi", CCM, CCGR3, OPENVGAXICLK_CLK_ROOT_ENABLE),
835 CLK_GATE("pcie_axi", "pcie_axi_sel", CCM, CCGR4, PCIE_ROOT_ENABLE),
836 CLK_GATE("per1_bch", "usdhc3", CCM, CCGR4, PL301_MX6QPER1_BCHCLK_ENABLE),
837 CLK_GATE("pwm1", "ipg_per", CCM, CCGR4, PWM1_CLK_ENABLE),
838 CLK_GATE("pwm2", "ipg_per", CCM, CCGR4, PWM2_CLK_ENABLE),
839 CLK_GATE("pwm3", "ipg_per", CCM, CCGR4, PWM3_CLK_ENABLE),
840 CLK_GATE("pwm4", "ipg_per", CCM, CCGR4, PWM4_CLK_ENABLE),
841 CLK_GATE("gpmi_bch_apb", "usdhc3", CCM, CCGR4, RAWNAND_U_BCH_INPUT_APB_CLK_ENABLE),
842 CLK_GATE("gpmi_bch", "usdhc4", CCM, CCGR4, RAWNAND_U_GPMI_BCH_INPUT_BCH_CLK_ENABLE),
843 CLK_GATE("gpmi_io", "enfc", CCM, CCGR4, RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_CLK_ENABLE),
844 CLK_GATE("gpmi_apb", "usdhc3", CCM, CCGR4, RAWNAND_U_GPMI_INPUT_APB_CLK_ENABLE),
845 CLK_GATE("rom", "ahb", CCM, CCGR5, ROM_CLK_ENABLE),
846 CLK_GATE("sata", "ahb", CCM, CCGR5, SATA_CLK_ENABLE),
847 CLK_GATE("sdma", "ahb", CCM, CCGR5, SDMA_CLK_ENABLE),
848 CLK_GATE("spba", "ipg", CCM, CCGR5, SPBA_CLK_ENABLE),
849 CLK_GATE("spdif", "spdif_podf", CCM, CCGR5, SPDIF_CLK_ENABLE),
850 CLK_GATE("spdif_gclk", "ipg", CCM, CCGR5, SPDIF_CLK_ENABLE),
851 CLK_GATE("ssi1_ipg", "ipg", CCM, CCGR5, SSI1_CLK_ENABLE),
852 CLK_GATE("ssi2_ipg", "ipg", CCM, CCGR5, SSI2_CLK_ENABLE),
853 CLK_GATE("ssi3_ipg", "ipg", CCM, CCGR5, SSI3_CLK_ENABLE),
854 CLK_GATE("ssi1", "ssi1_podf", CCM, CCGR5, SSI1_CLK_ENABLE),
855 CLK_GATE("ssi2", "ssi2_podf", CCM, CCGR5, SSI2_CLK_ENABLE),
856 CLK_GATE("ssi3", "ssi3_podf", CCM, CCGR5, SSI3_CLK_ENABLE),
857 CLK_GATE("uart_ipg", "ipg", CCM, CCGR5, UART_CLK_ENABLE),
858 CLK_GATE("uart_serial", "uart_serial_podf", CCM, CCGR5, UART_SERIAL_CLK_ENABLE),
859 CLK_GATE("usboh3", "ipg", CCM, CCGR6, USBOH3_CLK_ENABLE),
860 CLK_GATE("usdhc1", "usdhc1_podf", CCM, CCGR6, USDHC1_CLK_ENABLE),
861 CLK_GATE("usdhc2", "usdhc2_podf", CCM, CCGR6, USDHC2_CLK_ENABLE),
862 CLK_GATE("usdhc3", "usdhc3_podf", CCM, CCGR6, USDHC3_CLK_ENABLE),
863 CLK_GATE("usdhc4", "usdhc4_podf", CCM, CCGR6, USDHC4_CLK_ENABLE),
864 CLK_GATE("eim_slow", "eim_slow_podf", CCM, CCGR6, EIM_SLOW_CLK_ENABLE),
865 CLK_GATE("vdo_axi", "vdo_axi_sel", CCM, CCGR6, VDOAXICLK_CLK_ENABLE),
866 CLK_GATE("vpu_axi", "vpu_axi_podf", CCM, CCGR6, VPU_CLK_ENABLE),
867 CLK_GATE("cko1", "cko1_podf", CCM, CCOSR, CLKO1_EN),
868 CLK_GATE("cko2", "cko2_podf", CCM, CCOSR, CLKO2_EN),
869
870 CLK_GATE("sata_ref_100m", "sata_ref", CCM_ANALOG, PLL_ENET, ENABLE_100M),
871 CLK_GATE("pcie_ref_125m", "pcie_ref", CCM_ANALOG, PLL_ENET, ENABLE_125M),
872
873 CLK_GATE("pll1_sys", "pll1_bypass", CCM_ANALOG, PLL_ARM, ENABLE),
874 CLK_GATE("pll2_bus", "pll2_bypass", CCM_ANALOG, PLL_SYS, ENABLE),
875 CLK_GATE("pll3_usb_otg", "pll3_bypass", CCM_ANALOG, PLL_USB1, ENABLE),
876 CLK_GATE("pll4_audio", "pll4_bypass", CCM_ANALOG, PLL_AUDIO, ENABLE),
877 CLK_GATE("pll5_video", "pll5_bypass", CCM_ANALOG, PLL_VIDEO, ENABLE),
878 CLK_GATE("pll6_enet", "pll6_bypass", CCM_ANALOG, PLL_ENET, ENABLE),
879 CLK_GATE("pll7_usb_host", "pll7_bypass", CCM_ANALOG, PLL_USB2, ENABLE),
880
881 CLK_GATE("usbphy1", "pll3_usb_otg", CCM_ANALOG, PLL_USB1, RESERVED),
882 CLK_GATE("usbphy2", "pll7_usb_host", CCM_ANALOG, PLL_USB2, RESERVED),
883
884 CLK_GATE_EXCLUSIVE("lvds1_gate", "lvds1_sel", CCM_ANALOG, MISC1, LVDS_CLK1_OBEN, LVDS_CLK1_IBEN),
885 CLK_GATE_EXCLUSIVE("lvds2_gate", "lvds2_sel", CCM_ANALOG, MISC1, LVDS_CLK2_OBEN, LVDS_CLK2_IBEN),
886 CLK_GATE_EXCLUSIVE("lvds1_in", "anaclk1", CCM_ANALOG, MISC1, LVDS_CLK1_IBEN, LVDS_CLK1_OBEN),
887 CLK_GATE_EXCLUSIVE("lvds2_in", "anaclk2", CCM_ANALOG, MISC1, LVDS_CLK2_IBEN, LVDS_CLK2_OBEN),
888 };
889
890 static struct imx6_clk *imx6_clk_find(const char *);
891 static struct imx6_clk *imx6_clk_find_by_id(u_int);
892
893 static void imxccm_init_clocks(struct imx6ccm_softc *);
894 static struct clk *imxccm_clk_get(void *, const char *);
895 static void imxccm_clk_put(void *, struct clk *);
896 static u_int imxccm_clk_get_rate(void *, struct clk *);
897 static int imxccm_clk_set_rate(void *, struct clk *, u_int);
898 static int imxccm_clk_enable(void *, struct clk *);
899 static int imxccm_clk_disable(void *, struct clk *);
900 static int imxccm_clk_set_parent(void *, struct clk *, struct clk *);
901 static struct clk *imxccm_clk_get_parent(void *, struct clk *);
902
903 static const struct clk_funcs imxccm_clk_funcs = {
904 .get = imxccm_clk_get,
905 .put = imxccm_clk_put,
906 .get_rate = imxccm_clk_get_rate,
907 .set_rate = imxccm_clk_set_rate,
908 .enable = imxccm_clk_enable,
909 .disable = imxccm_clk_disable,
910 .set_parent = imxccm_clk_set_parent,
911 .get_parent = imxccm_clk_get_parent,
912 };
913
914 void
915 imx6ccm_attach_common(device_t self)
916 {
917 struct imx6ccm_softc * const sc = device_private(self);
918
919 sc->sc_dev = self;
920
921 sc->sc_clkdom.name = device_xname(self);
922 sc->sc_clkdom.funcs = &imxccm_clk_funcs;
923 sc->sc_clkdom.priv = sc;
924 for (u_int n = 0; n < __arraycount(imx6_clks); n++) {
925 imx6_clks[n].base.domain = &sc->sc_clkdom;
926 clk_attach(&imx6_clks[n].base);
927 }
928
929 imxccm_init_clocks(sc);
930
931 for (int n = 0; n < __arraycount(imx6_clks); n++) {
932 struct clk *clk = &imx6_clks[n].base;
933 struct clk *clk_parent = clk_get_parent(clk);
934 const char *parent_str = clk_parent ? clk_parent->name : "none";
935 aprint_verbose_dev(self, "%s (%s) : %u Hz\n", clk->name,
936 parent_str, clk_get_rate(clk));
937 }
938 }
939
940 struct clk *
941 imx6_get_clock(const char *name)
942 {
943 struct imx6_clk *iclk;
944 iclk = imx6_clk_find(name);
945
946 if (iclk == NULL)
947 return NULL;
948
949 return &iclk->base;
950 }
951
952 struct clk *
953 imx6_get_clock_by_id(u_int clock_id)
954 {
955 struct imx6_clk *iclk;
956 iclk = imx6_clk_find_by_id(clock_id);
957
958 if (iclk == NULL)
959 return NULL;
960
961 return &iclk->base;
962 }
963
964 static struct imx6_clk *
965 imx6_clk_find(const char *name)
966 {
967 if (name == NULL)
968 return NULL;
969
970 for (int n = 0; n < __arraycount(imx6_clks); n++) {
971 if (strcmp(imx6_clks[n].base.name, name) == 0)
972 return &imx6_clks[n];
973 }
974
975 return NULL;
976 }
977
978 static struct imx6_clk *
979 imx6_clk_find_by_id(u_int clock_id)
980 {
981 for (int n = 0; n < __arraycount(imx6_clock_ids); n++) {
982 if (imx6_clock_ids[n].id == clock_id) {
983 const char *name = imx6_clock_ids[n].name;
984 return imx6_clk_find(name);
985 }
986 }
987
988 return NULL;
989 }
990
991 struct imxccm_init_parent {
992 const char *clock;
993 const char *parent;
994 } imxccm_init_parents[] = {
995 { "pll1_bypass", "pll1" },
996 { "pll2_bypass", "pll2" },
997 { "pll3_bypass", "pll3" },
998 { "pll4_bypass", "pll4" },
999 { "pll5_bypass", "pll5" },
1000 { "pll6_bypass", "pll6" },
1001 { "pll7_bypass", "pll7" },
1002 { "lvds1_sel", "sata_ref_100m" },
1003 };
1004
1005 static void
1006 imxccm_init_clocks(struct imx6ccm_softc *sc)
1007 {
1008 struct clk *clk;
1009 struct clk *clk_parent;
1010
1011 for (u_int n = 0; n < __arraycount(imxccm_init_parents); n++) {
1012 clk = clk_get(&sc->sc_clkdom, imxccm_init_parents[n].clock);
1013 KASSERT(clk != NULL);
1014 clk_parent = clk_get(&sc->sc_clkdom, imxccm_init_parents[n].parent);
1015 KASSERT(clk_parent != NULL);
1016
1017 int error = clk_set_parent(clk, clk_parent);
1018 if (error) {
1019 aprint_error_dev(sc->sc_dev,
1020 "couldn't set '%s' parent to '%s': %d\n",
1021 clk->name, clk_parent->name, error);
1022 }
1023 clk_put(clk_parent);
1024 clk_put(clk);
1025 }
1026 }
1027
1028 static u_int
1029 imxccm_clk_get_rate_pll_generic(struct imx6ccm_softc *sc, struct imx6_clk *iclk,
1030 const u_int rate_parent)
1031 {
1032 struct imx6_clk_pll *pll = &iclk->clk.pll;
1033 uint64_t freq = rate_parent;
1034
1035 KASSERT((pll->type == IMX6_CLK_PLL_GENERIC) ||
1036 (pll->type == IMX6_CLK_PLL_USB));
1037
1038 uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg);
1039 uint32_t div = __SHIFTOUT(v, pll->mask);
1040
1041 return freq * ((div == 1) ? 22 : 20);
1042 }
1043
1044 static u_int
1045 imxccm_clk_get_rate_pll_sys(struct imx6ccm_softc *sc, struct imx6_clk *iclk,
1046 const u_int rate_parent)
1047 {
1048 struct imx6_clk_pll *pll = &iclk->clk.pll;
1049 uint64_t freq = rate_parent;
1050
1051 KASSERT(pll->type == IMX6_CLK_PLL_SYS);
1052
1053 uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg);
1054 uint32_t div = __SHIFTOUT(v, pll->mask);
1055
1056 return freq * div / 2;
1057 }
1058
1059 #define PLL_AUDIO_VIDEO_NUM_OFFSET 0x10
1060 #define PLL_AUDIO_VIDEO_DENOM_OFFSET 0x20
1061
1062 static u_int
1063 imxccm_clk_get_rate_pll_audio_video(struct imx6ccm_softc *sc,
1064 struct imx6_clk *iclk, const u_int rate_parent)
1065 {
1066 struct imx6_clk_pll *pll = &iclk->clk.pll;
1067 uint64_t freq = rate_parent;
1068
1069 KASSERT(pll->type == IMX6_CLK_PLL_AUDIO_VIDEO);
1070
1071 uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pll->reg);
1072 uint32_t div = __SHIFTOUT(v, pll->mask);
1073 uint32_t num = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog,
1074 pll->reg + PLL_AUDIO_VIDEO_NUM_OFFSET);
1075 uint32_t denom = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog,
1076 pll->reg + PLL_AUDIO_VIDEO_DENOM_OFFSET);
1077
1078 uint64_t tmp = freq * num / denom;
1079
1080 return freq * div + tmp;
1081 }
1082
1083 static u_int
1084 imxccm_clk_get_rate_pll_enet(struct imx6ccm_softc *sc,
1085 struct imx6_clk *iclk, const u_int rate_parent)
1086 {
1087 struct imx6_clk_pll *pll = &iclk->clk.pll;
1088
1089 KASSERT(pll->type == IMX6_CLK_PLL_ENET);
1090
1091 return pll->ref;
1092 }
1093
1094 static u_int
1095 imxccm_clk_get_rate_fixed_factor(struct imx6ccm_softc *sc, struct imx6_clk *iclk)
1096 {
1097 struct imx6_clk_fixed_factor *fixed_factor = &iclk->clk.fixed_factor;
1098 struct imx6_clk *parent;
1099
1100 KASSERT(iclk->type == IMX6_CLK_FIXED_FACTOR);
1101
1102 parent = imx6_clk_find(iclk->parent);
1103 KASSERT(parent != NULL);
1104
1105 uint64_t rate_parent = imxccm_clk_get_rate(sc, &parent->base);
1106
1107 return rate_parent * fixed_factor->mult / fixed_factor->div;
1108 }
1109
1110 static u_int
1111 imxccm_clk_get_rate_pll(struct imx6ccm_softc *sc, struct imx6_clk *iclk)
1112 {
1113 struct imx6_clk_pll *pll = &iclk->clk.pll;
1114 struct imx6_clk *parent;
1115
1116 KASSERT(iclk->type == IMX6_CLK_PLL);
1117
1118 parent = imx6_clk_find(iclk->parent);
1119 KASSERT(parent != NULL);
1120
1121 uint64_t rate_parent = imxccm_clk_get_rate(sc, &parent->base);
1122
1123 switch(pll->type) {
1124 case IMX6_CLK_PLL_GENERIC:
1125 return imxccm_clk_get_rate_pll_generic(sc, iclk, rate_parent);
1126 case IMX6_CLK_PLL_SYS:
1127 return imxccm_clk_get_rate_pll_sys(sc, iclk, rate_parent);
1128 case IMX6_CLK_PLL_USB:
1129 return imxccm_clk_get_rate_pll_generic(sc, iclk, rate_parent);
1130 case IMX6_CLK_PLL_AUDIO_VIDEO:
1131 return imxccm_clk_get_rate_pll_audio_video(sc, iclk, rate_parent);
1132 case IMX6_CLK_PLL_ENET:
1133 return imxccm_clk_get_rate_pll_enet(sc, iclk, rate_parent);
1134 default:
1135 panic("imx6: unknown pll type %d", iclk->type);
1136 }
1137 }
1138
1139 static u_int
1140 imxccm_clk_get_rate_div(struct imx6ccm_softc *sc, struct imx6_clk *iclk)
1141 {
1142 struct imx6_clk_div *div = &iclk->clk.div;
1143 struct imx6_clk *parent;
1144
1145 KASSERT(iclk->type == IMX6_CLK_DIV);
1146
1147 parent = imx6_clk_find(iclk->parent);
1148 KASSERT(parent != NULL);
1149
1150 u_int rate = imxccm_clk_get_rate(sc, &parent->base);
1151
1152 bus_space_handle_t ioh;
1153 if (div->base == IMX6_CLK_REG_CCM_ANALOG)
1154 ioh = sc->sc_ioh_analog;
1155 else
1156 ioh = sc->sc_ioh;
1157
1158 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, div->reg);
1159 uint32_t n = __SHIFTOUT(v, div->mask);
1160
1161 if (div->type == IMX6_CLK_DIV_TABLE) {
1162 KASSERT(div->tbl != NULL);
1163
1164 for (int i = 0; div->tbl[i] != 0; i++)
1165 if (i == n)
1166 rate /= div->tbl[i];
1167 } else {
1168 rate /= n + 1;
1169 }
1170
1171 return rate;
1172 }
1173
1174 static u_int
1175 imxccm_clk_get_rate_pfd(struct imx6ccm_softc *sc, struct imx6_clk *iclk)
1176 {
1177 struct imx6_clk_pfd *pfd = &iclk->clk.pfd;
1178 struct imx6_clk *parent;
1179
1180 KASSERT(iclk->type == IMX6_CLK_PFD);
1181
1182 parent = imx6_clk_find(iclk->parent);
1183 KASSERT(parent != NULL);
1184
1185 uint64_t rate_parent = imxccm_clk_get_rate(sc, &parent->base);
1186
1187 uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh_analog, pfd->reg);
1188 uint32_t n = __SHIFTOUT(v, __BITS(5, 0) << (pfd->index * 8));
1189
1190 KASSERT(n != 0);
1191
1192 return (rate_parent * 18) / n;
1193 }
1194
1195 static int
1196 imxccm_clk_mux_wait(struct imx6ccm_softc *sc, struct imx6_clk_mux *mux)
1197 {
1198 KASSERT(mux->busy_reg == 0);
1199 KASSERT(mux->busy_mask == 0);
1200
1201 bus_space_handle_t ioh;
1202 if (mux->base == IMX6_CLK_REG_CCM_ANALOG)
1203 ioh = sc->sc_ioh_analog;
1204 else
1205 ioh = sc->sc_ioh;
1206
1207 while (bus_space_read_4(sc->sc_iot, ioh, mux->busy_reg) & mux->busy_mask)
1208 delay(10);
1209
1210 return 0;
1211 }
1212
1213 static int
1214 imxccm_clk_set_parent_mux(struct imx6ccm_softc *sc,
1215 struct imx6_clk *iclk, struct clk *parent)
1216 {
1217 struct imx6_clk_mux *mux = &iclk->clk.mux;
1218 const char *pname = parent->name;
1219 u_int sel;
1220
1221 KASSERT(iclk->type == IMX6_CLK_MUX);
1222
1223 for (sel = 0; sel < mux->nparents; sel++)
1224 if (strcmp(pname, mux->parents[sel]) == 0)
1225 break;
1226
1227 if (sel == mux->nparents)
1228 return EINVAL;
1229
1230 bus_space_handle_t ioh;
1231 if (mux->base == IMX6_CLK_REG_CCM_ANALOG)
1232 ioh = sc->sc_ioh_analog;
1233 else
1234 ioh = sc->sc_ioh;
1235
1236 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, mux->reg);
1237 v &= ~mux->mask;
1238 v |= __SHIFTIN(sel, mux->mask);
1239
1240 bus_space_write_4(sc->sc_iot, ioh, mux->reg, v);
1241
1242 iclk->parent = pname;
1243
1244 if (mux->type == IMX6_CLK_MUX_BUSY)
1245 imxccm_clk_mux_wait(sc, mux);
1246
1247 return 0;
1248 }
1249
1250 static struct imx6_clk *
1251 imxccm_clk_get_parent_mux(struct imx6ccm_softc *sc, struct imx6_clk *iclk)
1252 {
1253 struct imx6_clk_mux *mux = &iclk->clk.mux;
1254
1255 KASSERT(iclk->type == IMX6_CLK_MUX);
1256
1257 bus_space_handle_t ioh;
1258 if (mux->base == IMX6_CLK_REG_CCM_ANALOG)
1259 ioh = sc->sc_ioh_analog;
1260 else
1261 ioh = sc->sc_ioh;
1262
1263 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, mux->reg);
1264 u_int sel = __SHIFTOUT(v, mux->mask);
1265
1266 KASSERT(sel < mux->nparents);
1267
1268 iclk->parent = mux->parents[sel];
1269
1270 return imx6_clk_find(iclk->parent);
1271 }
1272
1273 static int
1274 imxccm_clk_set_rate_pll(struct imx6ccm_softc *sc,
1275 struct imx6_clk *iclk, u_int rate)
1276 {
1277 /* ToDo */
1278
1279 return EOPNOTSUPP;
1280 }
1281
1282 static int
1283 imxccm_clk_set_rate_div(struct imx6ccm_softc *sc,
1284 struct imx6_clk *iclk, u_int rate)
1285 {
1286 struct imx6_clk_div *div = &iclk->clk.div;
1287 struct imx6_clk *parent;
1288
1289 KASSERT(iclk->type == IMX6_CLK_DIV);
1290
1291 parent = imx6_clk_find(iclk->parent);
1292 KASSERT(parent != NULL);
1293
1294 u_int rate_parent = imxccm_clk_get_rate(sc, &parent->base);
1295 u_int divider = uimax(1, rate_parent / rate);
1296
1297 bus_space_handle_t ioh;
1298 if (div->base == IMX6_CLK_REG_CCM_ANALOG)
1299 ioh = sc->sc_ioh_analog;
1300 else
1301 ioh = sc->sc_ioh;
1302
1303 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, div->reg);
1304 v &= ~div->mask;
1305 if (div->type == IMX6_CLK_DIV_TABLE) {
1306 int n = -1;
1307
1308 KASSERT(div->tbl != NULL);
1309 for (int i = 0; div->tbl[i] != 0; i++)
1310 if (div->tbl[i] == divider)
1311 n = i;
1312
1313 if (n >= 0)
1314 v |= __SHIFTIN(n, div->mask);
1315 else
1316 return EINVAL;
1317 } else {
1318 v |= __SHIFTIN(divider - 1, div->mask);
1319 }
1320 bus_space_write_4(sc->sc_iot, ioh, div->reg, v);
1321
1322 return 0;
1323 }
1324
1325 /*
1326 * CLK Driver APIs
1327 */
1328 static struct clk *
1329 imxccm_clk_get(void *priv, const char *name)
1330 {
1331 struct imx6_clk *iclk;
1332
1333 iclk = imx6_clk_find(name);
1334 if (iclk == NULL)
1335 return NULL;
1336
1337 atomic_inc_uint(&iclk->refcnt);
1338
1339 return &iclk->base;
1340 }
1341
1342 static void
1343 imxccm_clk_put(void *priv, struct clk *clk)
1344 {
1345 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1346
1347 KASSERT(iclk->refcnt > 0);
1348
1349 atomic_dec_uint(&iclk->refcnt);
1350 }
1351
1352 static u_int
1353 imxccm_clk_get_rate(void *priv, struct clk *clk)
1354 {
1355 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1356 struct clk *parent;
1357 struct imx6ccm_softc *sc = priv;
1358
1359 switch (iclk->type) {
1360 case IMX6_CLK_FIXED:
1361 return iclk->clk.fixed.rate;
1362 case IMX6_CLK_FIXED_FACTOR:
1363 return imxccm_clk_get_rate_fixed_factor(sc, iclk);
1364 case IMX6_CLK_PLL:
1365 return imxccm_clk_get_rate_pll(sc, iclk);
1366 case IMX6_CLK_MUX:
1367 case IMX6_CLK_GATE:
1368 parent = imxccm_clk_get_parent(sc, clk);
1369 return imxccm_clk_get_rate(sc, parent);
1370 case IMX6_CLK_DIV:
1371 return imxccm_clk_get_rate_div(sc, iclk);
1372 case IMX6_CLK_PFD:
1373 return imxccm_clk_get_rate_pfd(sc, iclk);
1374 default:
1375 panic("imx6: unknown clk type %d", iclk->type);
1376 }
1377 }
1378
1379 static int
1380 imxccm_clk_set_rate(void *priv, struct clk *clk, u_int rate)
1381 {
1382 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1383 struct imx6ccm_softc *sc = priv;
1384
1385 switch (iclk->type) {
1386 case IMX6_CLK_FIXED:
1387 case IMX6_CLK_FIXED_FACTOR:
1388 return ENXIO;
1389 case IMX6_CLK_PLL:
1390 return imxccm_clk_set_rate_pll(sc, iclk, rate);
1391 case IMX6_CLK_MUX:
1392 return ENXIO;
1393 case IMX6_CLK_GATE:
1394 return ENXIO;
1395 case IMX6_CLK_DIV:
1396 return imxccm_clk_set_rate_div(sc, iclk, rate);
1397 case IMX6_CLK_PFD:
1398 return EINVAL;
1399 default:
1400 panic("imx6: unknown clk type %d", iclk->type);
1401 }
1402 }
1403
1404 static int
1405 imxccm_clk_enable_pll(struct imx6ccm_softc *sc, struct imx6_clk *iclk, bool enable)
1406 {
1407 struct imx6_clk_pll *pll = &iclk->clk.pll;
1408
1409 KASSERT(iclk->type == IMX6_CLK_PLL);
1410
1411 /* Power up bit */
1412 if (pll->type == IMX6_CLK_PLL_USB)
1413 enable = !enable;
1414
1415 bus_space_handle_t ioh = sc->sc_ioh_analog;
1416 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, pll->reg);
1417 if (__SHIFTOUT(v, pll->powerdown) != enable)
1418 return 0;
1419 if (enable)
1420 v &= ~pll->powerdown;
1421 else
1422 v |= pll->powerdown;
1423 bus_space_write_4(sc->sc_iot, ioh, pll->reg, v);
1424
1425 /* wait look */
1426 while (!(bus_space_read_4(sc->sc_iot, ioh, pll->reg) & CCM_ANALOG_PLL_LOCK))
1427 delay(10);
1428
1429 return 0;
1430 }
1431
1432 static int
1433 imxccm_clk_enable_gate(struct imx6ccm_softc *sc, struct imx6_clk *iclk, bool enable)
1434 {
1435 struct imx6_clk_gate *gate = &iclk->clk.gate;
1436
1437 KASSERT(iclk->type == IMX6_CLK_GATE);
1438
1439 bus_space_handle_t ioh;
1440 if (gate->base == IMX6_CLK_REG_CCM_ANALOG)
1441 ioh = sc->sc_ioh_analog;
1442 else
1443 ioh = sc->sc_ioh;
1444
1445 uint32_t v = bus_space_read_4(sc->sc_iot, ioh, gate->reg);
1446 if (enable) {
1447 if (gate->exclusive_mask)
1448 v &= ~gate->exclusive_mask;
1449 v |= gate->mask;
1450 } else {
1451 if (gate->exclusive_mask)
1452 v |= gate->exclusive_mask;
1453 v &= ~gate->mask;
1454 }
1455 bus_space_write_4(sc->sc_iot, ioh, gate->reg, v);
1456
1457 return 0;
1458 }
1459
1460 static int
1461 imxccm_clk_enable(void *priv, struct clk *clk)
1462 {
1463 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1464 struct imx6_clk *parent = NULL;
1465 struct imx6ccm_softc *sc = priv;
1466
1467 if ((parent = imx6_clk_find(iclk->parent)) != NULL)
1468 imxccm_clk_enable(sc, &parent->base);
1469
1470 switch (iclk->type) {
1471 case IMX6_CLK_FIXED:
1472 case IMX6_CLK_FIXED_FACTOR:
1473 return 0; /* always on */
1474 case IMX6_CLK_PLL:
1475 return imxccm_clk_enable_pll(sc, iclk, true);
1476 case IMX6_CLK_MUX:
1477 case IMX6_CLK_DIV:
1478 case IMX6_CLK_PFD:
1479 return 0;
1480 case IMX6_CLK_GATE:
1481 return imxccm_clk_enable_gate(sc, iclk, true);
1482 default:
1483 panic("imx6: unknown clk type %d", iclk->type);
1484 }
1485 }
1486
1487 static int
1488 imxccm_clk_disable(void *priv, struct clk *clk)
1489 {
1490 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1491 struct imx6ccm_softc *sc = priv;
1492
1493 switch (iclk->type) {
1494 case IMX6_CLK_FIXED:
1495 case IMX6_CLK_FIXED_FACTOR:
1496 return EINVAL; /* always on */
1497 case IMX6_CLK_PLL:
1498 return imxccm_clk_enable_pll(sc, iclk, false);
1499 case IMX6_CLK_MUX:
1500 case IMX6_CLK_DIV:
1501 case IMX6_CLK_PFD:
1502 return EINVAL;
1503 case IMX6_CLK_GATE:
1504 return imxccm_clk_enable_gate(sc, iclk, false);
1505 default:
1506 panic("imx6: unknown clk type %d", iclk->type);
1507 }
1508 }
1509
1510 static int
1511 imxccm_clk_set_parent(void *priv, struct clk *clk, struct clk *parent)
1512 {
1513 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1514 struct imx6ccm_softc *sc = priv;
1515
1516 switch (iclk->type) {
1517 case IMX6_CLK_FIXED:
1518 case IMX6_CLK_FIXED_FACTOR:
1519 case IMX6_CLK_PLL:
1520 case IMX6_CLK_GATE:
1521 case IMX6_CLK_DIV:
1522 case IMX6_CLK_PFD:
1523 return EINVAL;
1524 case IMX6_CLK_MUX:
1525 return imxccm_clk_set_parent_mux(sc, iclk, parent);
1526 default:
1527 panic("imx6: unknown clk type %d", iclk->type);
1528 }
1529 }
1530
1531 static struct clk *
1532 imxccm_clk_get_parent(void *priv, struct clk *clk)
1533 {
1534 struct imx6_clk *iclk = (struct imx6_clk *)clk;
1535 struct imx6_clk *parent = NULL;
1536 struct imx6ccm_softc *sc = priv;
1537
1538 switch (iclk->type) {
1539 case IMX6_CLK_FIXED:
1540 case IMX6_CLK_FIXED_FACTOR:
1541 case IMX6_CLK_PLL:
1542 case IMX6_CLK_GATE:
1543 case IMX6_CLK_DIV:
1544 case IMX6_CLK_PFD:
1545 if (iclk->parent != NULL)
1546 parent = imx6_clk_find(iclk->parent);
1547 break;
1548 case IMX6_CLK_MUX:
1549 parent = imxccm_clk_get_parent_mux(sc, iclk);
1550 break;
1551 default:
1552 panic("imx6: unknown clk type %d", iclk->type);
1553 }
1554
1555 return (struct clk *)parent;
1556 }
1557