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