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