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