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