xref: /netbsd-src/sys/arch/arm/nxp/imx6_ccm.c (revision 7d62b00eb9ad855ffcd7da46b41e23feb5476fac)
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