imx51_ccm.c revision 330897
1/* $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $ */ 2/*- 3 * SPDX-License-Identifier: BSD-2-Clause AND BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2010, 2011, 2012 Genetec Corporation. All rights reserved. 6 * Written by Hashimoto Kenichi for Genetec Corporation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30/*- 31 * Copyright (c) 2012, 2013 The FreeBSD Foundation 32 * All rights reserved. 33 * 34 * Portions of this software were developed by Oleksandr Rybalko 35 * under sponsorship from the FreeBSD Foundation. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59/* 60 * Clock Controller Module (CCM) 61 */ 62 63#include <sys/cdefs.h> 64__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/imx51_ccm.c 330897 2018-03-14 03:19:51Z eadler $"); 65 66#include <sys/param.h> 67#include <sys/systm.h> 68#include <sys/bus.h> 69#include <sys/kernel.h> 70#include <sys/module.h> 71#include <sys/malloc.h> 72#include <sys/rman.h> 73#include <machine/bus.h> 74#include <machine/cpu.h> 75#include <machine/intr.h> 76 77#include <dev/fdt/fdt_common.h> 78#include <dev/ofw/openfirm.h> 79#include <dev/ofw/ofw_bus.h> 80#include <dev/ofw/ofw_bus_subr.h> 81 82#include <machine/bus.h> 83#include <machine/fdt.h> 84 85#include <arm/freescale/imx/imx51_ccmvar.h> 86#include <arm/freescale/imx/imx51_ccmreg.h> 87#include <arm/freescale/imx/imx51_dpllreg.h> 88#include <arm/freescale/imx/imx_ccmvar.h> 89#include <arm/freescale/imx/imx_machdep.h> 90 91#define IMXCCMDEBUG 92#undef IMXCCMDEBUG 93 94#ifndef IMX51_OSC_FREQ 95#define IMX51_OSC_FREQ (24 * 1000 * 1000) /* 24MHz */ 96#endif 97 98#ifndef IMX51_CKIL_FREQ 99#define IMX51_CKIL_FREQ 32768 100#endif 101 102/* 103 * The fdt data does not provide reg properties describing the DPLL register 104 * blocks we need to access, presumably because the needed addresses are 105 * hard-coded within the linux driver. That leaves us with no choice but to do 106 * the same thing, if we want to run with vendor-supplied fdt data. So here we 107 * have tables of the physical addresses we need for each soc, and we'll use 108 * bus_space_map() at attach() time to get access to them. 109 */ 110static uint32_t imx51_dpll_addrs[IMX51_N_DPLLS] = { 111 0x83f80000, /* DPLL1 */ 112 0x83f84000, /* DPLL2 */ 113 0x83f88000, /* DPLL3 */ 114}; 115 116static uint32_t imx53_dpll_addrs[IMX51_N_DPLLS] = { 117 0x63f80000, /* DPLL1 */ 118 0x63f84000, /* DPLL2 */ 119 0x63f88000, /* DPLL3 */ 120}; 121 122#define DPLL_REGS_SZ (16 * 1024) 123 124struct imxccm_softc { 125 device_t sc_dev; 126 struct resource *ccmregs; 127 u_int64_t pll_freq[IMX51_N_DPLLS]; 128 bus_space_tag_t pllbst; 129 bus_space_handle_t pllbsh[IMX51_N_DPLLS]; 130}; 131 132struct imxccm_softc *ccm_softc = NULL; 133 134static uint64_t imx51_get_pll_freq(u_int); 135 136static int imxccm_match(device_t); 137static int imxccm_attach(device_t); 138 139static device_method_t imxccm_methods[] = { 140 DEVMETHOD(device_probe, imxccm_match), 141 DEVMETHOD(device_attach, imxccm_attach), 142 143 DEVMETHOD_END 144}; 145 146static driver_t imxccm_driver = { 147 "imxccm", 148 imxccm_methods, 149 sizeof(struct imxccm_softc), 150}; 151 152static devclass_t imxccm_devclass; 153 154EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0, 155 BUS_PASS_CPU); 156 157static inline uint32_t 158pll_read_4(struct imxccm_softc *sc, int pll, int reg) 159{ 160 161 return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg)); 162} 163 164static inline uint32_t 165ccm_read_4(struct imxccm_softc *sc, int reg) 166{ 167 168 return (bus_read_4(sc->ccmregs, reg)); 169} 170 171static inline void 172ccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val) 173{ 174 175 bus_write_4(sc->ccmregs, reg, val); 176} 177 178static int 179imxccm_match(device_t dev) 180{ 181 182 if (!ofw_bus_status_okay(dev)) 183 return (ENXIO); 184 185 if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") && 186 !ofw_bus_is_compatible(dev, "fsl,imx53-ccm")) 187 return (ENXIO); 188 189 device_set_desc(dev, "Freescale Clock Control Module"); 190 return (BUS_PROBE_DEFAULT); 191} 192 193static int 194imxccm_attach(device_t dev) 195{ 196 struct imxccm_softc *sc; 197 int idx; 198 u_int soc; 199 uint32_t *pll_addrs; 200 201 sc = device_get_softc(dev); 202 sc->sc_dev = dev; 203 204 switch ((soc = imx_soc_type())) { 205 case IMXSOC_51: 206 pll_addrs = imx51_dpll_addrs; 207 break; 208 case IMXSOC_53: 209 pll_addrs = imx53_dpll_addrs; 210 break; 211 default: 212 device_printf(dev, "No support for SoC type 0x%08x\n", soc); 213 goto noclocks; 214 } 215 216 idx = 0; 217 sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx, 218 RF_ACTIVE); 219 if (sc->ccmregs == NULL) { 220 device_printf(dev, "could not allocate resources\n"); 221 goto noclocks; 222 } 223 224 sc->pllbst = fdtbus_bs_tag; 225 for (idx = 0; idx < IMX51_N_DPLLS; ++idx) { 226 if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0, 227 &sc->pllbsh[idx]) != 0) { 228 device_printf(dev, "Cannot map DPLL registers\n"); 229 goto noclocks; 230 } 231 } 232 233 ccm_softc = sc; 234 235 imx51_get_pll_freq(1); 236 imx51_get_pll_freq(2); 237 imx51_get_pll_freq(3); 238 239 device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n", 240 sc->pll_freq[0] / 1000000, 241 sc->pll_freq[1] / 1000000, 242 sc->pll_freq[2] / 1000000); 243 device_printf(dev, "CPU clock=%d, UART clock=%d\n", 244 imx51_get_clock(IMX51CLK_ARM_ROOT), 245 imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 246 device_printf(dev, 247 "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n", 248 imx51_get_clock(IMX51CLK_MAIN_BUS_CLK), 249 imx51_get_clock(IMX51CLK_AHB_CLK_ROOT), 250 imx51_get_clock(IMX51CLK_IPG_CLK_ROOT), 251 imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 252 253 254 return (0); 255 256noclocks: 257 258 panic("Cannot continue without clock support"); 259} 260 261u_int 262imx51_get_clock(enum imx51_clock clk) 263{ 264 u_int freq; 265 u_int sel; 266 uint32_t cacrr; /* ARM clock root register */ 267 uint32_t ccsr; 268 uint32_t cscdr1; 269 uint32_t cscmr1; 270 uint32_t cbcdr; 271 uint32_t cbcmr; 272 uint32_t cdcr; 273 274 if (ccm_softc == NULL) 275 return (0); 276 277 switch (clk) { 278 case IMX51CLK_PLL1: 279 case IMX51CLK_PLL2: 280 case IMX51CLK_PLL3: 281 return ccm_softc->pll_freq[clk-IMX51CLK_PLL1]; 282 case IMX51CLK_PLL1SW: 283 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 284 if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0) 285 return ccm_softc->pll_freq[1-1]; 286 /* step clock */ 287 /* FALLTHROUGH */ 288 case IMX51CLK_PLL1STEP: 289 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 290 switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) { 291 case 0: 292 return imx51_get_clock(IMX51CLK_LP_APM); 293 case 1: 294 return 0; /* XXX PLL bypass clock */ 295 case 2: 296 return ccm_softc->pll_freq[2-1] / 297 (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >> 298 CCSR_PLL2_DIV_PODF_SHIFT)); 299 case 3: 300 return ccm_softc->pll_freq[3-1] / 301 (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >> 302 CCSR_PLL3_DIV_PODF_SHIFT)); 303 } 304 /*NOTREACHED*/ 305 case IMX51CLK_PLL2SW: 306 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 307 if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0) 308 return imx51_get_clock(IMX51CLK_PLL2); 309 return 0; /* XXX PLL2 bypass clk */ 310 case IMX51CLK_PLL3SW: 311 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 312 if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0) 313 return imx51_get_clock(IMX51CLK_PLL3); 314 return 0; /* XXX PLL3 bypass clk */ 315 316 case IMX51CLK_LP_APM: 317 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 318 return (ccsr & CCSR_LP_APM) ? 319 imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ; 320 321 case IMX51CLK_ARM_ROOT: 322 freq = imx51_get_clock(IMX51CLK_PLL1SW); 323 cacrr = ccm_read_4(ccm_softc, CCMC_CACRR); 324 return freq / (cacrr + 1); 325 326 /* ... */ 327 case IMX51CLK_MAIN_BUS_CLK_SRC: 328 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 329 if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0) 330 freq = imx51_get_clock(IMX51CLK_PLL2SW); 331 else { 332 freq = 0; 333 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 334 switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >> 335 CBCMR_PERIPH_APM_SEL_SHIFT) { 336 case 0: 337 freq = imx51_get_clock(IMX51CLK_PLL1SW); 338 break; 339 case 1: 340 freq = imx51_get_clock(IMX51CLK_PLL3SW); 341 break; 342 case 2: 343 freq = imx51_get_clock(IMX51CLK_LP_APM); 344 break; 345 case 3: 346 /* XXX: error */ 347 break; 348 } 349 } 350 return freq; 351 case IMX51CLK_MAIN_BUS_CLK: 352 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 353 cdcr = ccm_read_4(ccm_softc, CCMC_CDCR); 354 return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >> 355 CDCR_PERIPH_CLK_DVFS_PODF_SHIFT)); 356 case IMX51CLK_AHB_CLK_ROOT: 357 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK); 358 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 359 return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >> 360 CBCDR_AHB_PODF_SHIFT)); 361 case IMX51CLK_IPG_CLK_ROOT: 362 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 363 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 364 return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >> 365 CBCDR_IPG_PODF_SHIFT)); 366 367 case IMX51CLK_PERCLK_ROOT: 368 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 369 if (cbcmr & CBCMR_PERCLK_IPG_SEL) 370 return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT); 371 if (cbcmr & CBCMR_PERCLK_LP_APM_SEL) 372 freq = imx51_get_clock(IMX51CLK_LP_APM); 373 else 374 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 375 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 376 377#ifdef IMXCCMDEBUG 378 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr); 379#endif 380 381 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >> 382 CBCDR_PERCLK_PRED1_SHIFT); 383 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >> 384 CBCDR_PERCLK_PRED2_SHIFT); 385 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >> 386 CBCDR_PERCLK_PODF_SHIFT); 387 return freq; 388 case IMX51CLK_UART_CLK_ROOT: 389 cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1); 390 cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1); 391 392#ifdef IMXCCMDEBUG 393 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1); 394#endif 395 396 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >> 397 CSCMR1_UART_CLK_SEL_SHIFT; 398 399 freq = 0; /* shut up GCC */ 400 switch (sel) { 401 case 0: 402 case 1: 403 case 2: 404 freq = imx51_get_clock(IMX51CLK_PLL1SW + sel); 405 break; 406 case 3: 407 freq = imx51_get_clock(IMX51CLK_LP_APM); 408 break; 409 } 410 411 return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >> 412 CSCDR1_UART_CLK_PRED_SHIFT)) / 413 (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >> 414 CSCDR1_UART_CLK_PODF_SHIFT)); 415 case IMX51CLK_IPU_HSP_CLK_ROOT: 416 freq = 0; 417 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 418 switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >> 419 CBCMR_IPU_HSP_CLK_SEL_SHIFT) { 420 case 0: 421 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK); 422 break; 423 case 1: 424 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK); 425 break; 426 case 2: 427 freq = imx51_get_clock( 428 IMX51CLK_EMI_SLOW_CLK_ROOT); 429 break; 430 case 3: 431 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 432 break; 433 } 434 return freq; 435 default: 436 device_printf(ccm_softc->sc_dev, 437 "clock %d: not supported yet\n", clk); 438 return 0; 439 } 440} 441 442 443static uint64_t 444imx51_get_pll_freq(u_int pll_no) 445{ 446 uint32_t dp_ctrl; 447 uint32_t dp_op; 448 uint32_t dp_mfd; 449 uint32_t dp_mfn; 450 uint32_t mfi; 451 int32_t mfn; 452 uint32_t mfd; 453 uint32_t pdf; 454 uint32_t ccr; 455 uint64_t freq = 0; 456 u_int ref = 0; 457 458 KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id")); 459 460 dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL); 461 462 if (dp_ctrl & DP_CTL_HFSM) { 463 dp_op = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP); 464 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD); 465 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN); 466 } else { 467 dp_op = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP); 468 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD); 469 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN); 470 } 471 472 pdf = dp_op & DP_OP_PDF_MASK; 473 mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT); 474 mfd = dp_mfd; 475 if (dp_mfn & 0x04000000) 476 /* 27bit signed value */ 477 mfn = (uint32_t)(0xf8000000 | dp_mfn); 478 else 479 mfn = dp_mfn; 480 481 switch (dp_ctrl & DP_CTL_REF_CLK_SEL_MASK) { 482 case DP_CTL_REF_CLK_SEL_COSC: 483 /* Internal Oscillator */ 484 /* TODO: get from FDT "fsl,imx-osc" */ 485 ref = 24000000; /* IMX51_OSC_FREQ */ 486 break; 487 case DP_CTL_REF_CLK_SEL_FPM: 488 ccr = ccm_read_4(ccm_softc, CCMC_CCR); 489 if (ccr & CCR_FPM_MULT) 490 /* TODO: get from FDT "fsl,imx-ckil" */ 491 ref = 32768 * 1024; 492 else 493 /* TODO: get from FDT "fsl,imx-ckil" */ 494 ref = 32768 * 512; 495 break; 496 default: 497 ref = 0; 498 } 499 500 if (dp_ctrl & DP_CTL_REF_CLK_DIV) 501 ref /= 2; 502 503 ref *= 4; 504 freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1); 505 freq /= pdf + 1; 506 507 if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN)) 508 freq /= 2; 509 510#ifdef IMXCCMDEBUG 511 printf("ref: %dKHz ", ref); 512 printf("dp_ctl: %08x ", dp_ctrl); 513 printf("pdf: %3d ", pdf); 514 printf("mfi: %3d ", mfi); 515 printf("mfd: %3d ", mfd); 516 printf("mfn: %3d ", mfn); 517 printf("pll: %d\n", (uint32_t)freq); 518#endif 519 520 ccm_softc->pll_freq[pll_no-1] = freq; 521 522 return (freq); 523} 524 525void 526imx51_clk_gating(int clk_src, int mode) 527{ 528 int field, group; 529 uint32_t reg; 530 531 group = CCMR_CCGR_MODULE(clk_src); 532 field = clk_src % CCMR_CCGR_NSOURCE; 533 reg = ccm_read_4(ccm_softc, CCMC_CCGR(group)); 534 reg &= ~(0x03 << field * 2); 535 reg |= (mode << field * 2); 536 ccm_write_4(ccm_softc, CCMC_CCGR(group), reg); 537} 538 539int 540imx51_get_clk_gating(int clk_src) 541{ 542 uint32_t reg; 543 544 reg = ccm_read_4(ccm_softc, 545 CCMC_CCGR(CCMR_CCGR_MODULE(clk_src))); 546 return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03); 547} 548 549/* 550 * Code from here down is temporary, in lieu of a SoC-independent clock API. 551 */ 552 553void 554imx_ccm_usb_enable(device_t dev) 555{ 556 uint32_t regval; 557 558 /* 559 * Select PLL2 as the source for the USB clock. 560 * The default is PLL3, but U-boot changes it to PLL2. 561 */ 562 regval = ccm_read_4(ccm_softc, CCMC_CSCMR1); 563 regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK; 564 regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT; 565 ccm_write_4(ccm_softc, CCMC_CSCMR1, regval); 566 567 /* 568 * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2. 569 */ 570 regval = ccm_read_4(ccm_softc, CCMC_CSCDR1); 571 regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK; 572 regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK; 573 regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT; 574 regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT; 575 ccm_write_4(ccm_softc, CCMC_CSCDR1, regval); 576 577 /* 578 * The same two clocks gates are used on imx51 and imx53. 579 */ 580 imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS); 581 imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS); 582} 583 584void 585imx_ccm_usbphy_enable(device_t dev) 586{ 587 uint32_t regval; 588 589 /* 590 * Select PLL3 as the source for the USBPHY clock. U-boot does this 591 * only for imx53, but the bit exists on imx51. That seems a bit 592 * strange, but we'll go with it until more is known. 593 */ 594 if (imx_soc_type() == IMXSOC_53) { 595 regval = ccm_read_4(ccm_softc, CCMC_CSCMR1); 596 regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT; 597 ccm_write_4(ccm_softc, CCMC_CSCMR1, regval); 598 } 599 600 /* 601 * For the imx51 there's just one phy gate control, enable it. 602 */ 603 if (imx_soc_type() == IMXSOC_51) { 604 imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS); 605 return; 606 } 607 608 /* 609 * For imx53 we don't have a full set of clock defines yet, but the 610 * datasheet says: 611 * gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable) 612 * gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable) 613 * 614 * We should use the fdt data for the device to figure out which of 615 * the two we're working on, but for now just turn them both on. 616 */ 617 if (imx_soc_type() == IMXSOC_53) { 618 imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS); 619 imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS); 620 return; 621 } 622} 623 624uint32_t 625imx_ccm_ipg_hz(void) 626{ 627 628 return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT)); 629} 630 631uint32_t 632imx_ccm_sdhci_hz(void) 633{ 634 635 return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT)); 636} 637 638uint32_t 639imx_ccm_perclk_hz(void) 640{ 641 642 return (imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 643} 644 645uint32_t 646imx_ccm_uart_hz(void) 647{ 648 649 return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 650} 651 652uint32_t 653imx_ccm_ahb_hz(void) 654{ 655 656 return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT)); 657} 658