1 /* $OpenBSD: imxccm.c,v 1.1 2018/04/02 16:47:39 patrick Exp $ */ 2 /* 3 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/queue.h> 21 #include <sys/malloc.h> 22 #include <sys/sysctl.h> 23 #include <sys/device.h> 24 #include <sys/evcount.h> 25 #include <sys/socket.h> 26 #include <sys/timeout.h> 27 28 #include <machine/intr.h> 29 #include <machine/bus.h> 30 #include <machine/fdt.h> 31 32 #include <dev/ofw/openfirm.h> 33 #include <dev/ofw/ofw_clock.h> 34 #include <dev/ofw/fdt.h> 35 36 /* registers */ 37 #define CCM_CCR 0x00 38 #define CCM_CCDR 0x04 39 #define CCM_CSR 0x08 40 #define CCM_CCSR 0x0c 41 #define CCM_CACRR 0x10 42 #define CCM_CBCDR 0x14 43 #define CCM_CBCMR 0x18 44 #define CCM_CSCMR1 0x1c 45 #define CCM_CSCMR2 0x20 46 #define CCM_CSCDR1 0x24 47 #define CCM_CS1CDR 0x28 48 #define CCM_CS2CDR 0x2c 49 #define CCM_CDCDR 0x30 50 #define CCM_CHSCCDR 0x34 51 #define CCM_CSCDR2 0x38 52 #define CCM_CSCDR3 0x3c 53 #define CCM_CSCDR4 0x40 54 #define CCM_CDHIPR 0x48 55 #define CCM_CDCR 0x4c 56 #define CCM_CTOR 0x50 57 #define CCM_CLPCR 0x54 58 #define CCM_CISR 0x58 59 #define CCM_CIMR 0x5c 60 #define CCM_CCOSR 0x60 61 #define CCM_CGPR 0x64 62 #define CCM_CCGR0 0x68 63 #define CCM_CCGR1 0x6c 64 #define CCM_CCGR2 0x70 65 #define CCM_CCGR3 0x74 66 #define CCM_CCGR4 0x78 67 #define CCM_CCGR5 0x7c 68 #define CCM_CCGR6 0x80 69 #define CCM_CCGR7 0x84 70 #define CCM_CMEOR 0x88 71 72 /* ANALOG */ 73 #define CCM_ANALOG_PLL_ARM 0x4000 74 #define CCM_ANALOG_PLL_ARM_SET 0x4004 75 #define CCM_ANALOG_PLL_ARM_CLR 0x4008 76 #define CCM_ANALOG_PLL_USB1 0x4010 77 #define CCM_ANALOG_PLL_USB1_SET 0x4014 78 #define CCM_ANALOG_PLL_USB1_CLR 0x4018 79 #define CCM_ANALOG_PLL_USB2 0x4020 80 #define CCM_ANALOG_PLL_USB2_SET 0x4024 81 #define CCM_ANALOG_PLL_USB2_CLR 0x4028 82 #define CCM_ANALOG_PLL_SYS 0x4030 83 #define CCM_ANALOG_USB1_CHRG_DETECT 0x41b0 84 #define CCM_ANALOG_USB1_CHRG_DETECT_SET 0x41b4 85 #define CCM_ANALOG_USB1_CHRG_DETECT_CLR 0x41b8 86 #define CCM_ANALOG_USB2_CHRG_DETECT 0x4210 87 #define CCM_ANALOG_USB2_CHRG_DETECT_SET 0x4214 88 #define CCM_ANALOG_USB2_CHRG_DETECT_CLR 0x4218 89 #define CCM_ANALOG_DIGPROG 0x4260 90 #define CCM_ANALOG_PLL_ENET 0x40e0 91 #define CCM_ANALOG_PLL_ENET_SET 0x40e4 92 #define CCM_ANALOG_PLL_ENET_CLR 0x40e8 93 #define CCM_ANALOG_PFD_480 0x40f0 94 #define CCM_ANALOG_PFD_480_SET 0x40f4 95 #define CCM_ANALOG_PFD_480_CLR 0x40f8 96 #define CCM_ANALOG_PFD_528 0x4100 97 #define CCM_ANALOG_PFD_528_SET 0x4104 98 #define CCM_ANALOG_PFD_528_CLR 0x4108 99 #define CCM_PMU_MISC1 0x4160 100 101 /* bits and bytes */ 102 #define CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0) 103 #define CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1) 104 #define CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) 105 #define CCM_CCSR_STEP_SEL (1 << 8) 106 #define CCM_CBCDR_IPG_PODF_SHIFT 8 107 #define CCM_CBCDR_IPG_PODF_MASK 0x3 108 #define CCM_CBCDR_AHB_PODF_SHIFT 10 109 #define CCM_CBCDR_AHB_PODF_MASK 0x7 110 #define CCM_CBCDR_PERIPH_CLK_SEL_SHIFT 25 111 #define CCM_CBCDR_PERIPH_CLK_SEL_MASK 0x1 112 #define CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT 12 113 #define CCM_CBCMR_PERIPH_CLK2_SEL_MASK 0x3 114 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT 18 115 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK 0x3 116 #define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x) ((x) + 15) 117 #define CCM_CSCDR1_USDHCx_CLK_SEL_MASK 0x1 118 #define CCM_CSCDR1_USDHCx_PODF_MASK 0x7 119 #define CCM_CSCDR1_UART_PODF_MASK 0x7 120 #define CCM_CCGR1_ENET (3 << 10) 121 #define CCM_CCGR4_125M_PCIE (3 << 0) 122 #define CCM_CCGR5_100M_SATA (3 << 4) 123 #define CCM_CSCMR1_PERCLK_CLK_PODF_MASK 0x1f 124 #define CCM_CSCMR1_PERCLK_CLK_SEL_MASK (1 << 6) 125 #define CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK 0x7f 126 #define CCM_ANALOG_PLL_ARM_BYPASS (1 << 16) 127 #define CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK 0x1 128 #define CCM_ANALOG_PLL_USB1_EN_USB_CLKS (1 << 6) 129 #define CCM_ANALOG_PLL_USB1_POWER (1 << 12) 130 #define CCM_ANALOG_PLL_USB1_ENABLE (1 << 13) 131 #define CCM_ANALOG_PLL_USB1_BYPASS (1 << 16) 132 #define CCM_ANALOG_PLL_USB1_LOCK (1 << 31) 133 #define CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK 0x1 134 #define CCM_ANALOG_PLL_USB2_EN_USB_CLKS (1 << 6) 135 #define CCM_ANALOG_PLL_USB2_POWER (1 << 12) 136 #define CCM_ANALOG_PLL_USB2_ENABLE (1 << 13) 137 #define CCM_ANALOG_PLL_USB2_BYPASS (1 << 16) 138 #define CCM_ANALOG_PLL_USB2_LOCK (1U << 31) 139 #define CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK 0x1 140 #define CCM_ANALOG_USB1_CHRG_DETECT_CHK_CHRG_B (1 << 19) 141 #define CCM_ANALOG_USB1_CHRG_DETECT_EN_B (1 << 20) 142 #define CCM_ANALOG_USB2_CHRG_DETECT_CHK_CHRG_B (1 << 19) 143 #define CCM_ANALOG_USB2_CHRG_DETECT_EN_B (1 << 20) 144 #define CCM_ANALOG_DIGPROG_MINOR_MASK 0xff 145 #define CCM_ANALOG_PLL_ENET_DIV_125M (1 << 11) 146 #define CCM_ANALOG_PLL_ENET_POWERDOWN (1 << 12) 147 #define CCM_ANALOG_PLL_ENET_ENABLE (1 << 13) 148 #define CCM_ANALOG_PLL_ENET_BYPASS (1 << 16) 149 #define CCM_ANALOG_PLL_ENET_125M_PCIE (1 << 19) 150 #define CCM_ANALOG_PLL_ENET_100M_SATA (1 << 20) 151 #define CCM_ANALOG_PLL_ENET_LOCK (1U << 31) 152 #define CCM_ANALOG_PFD_480_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f) 153 #define CCM_ANALOG_PFD_528_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f) 154 #define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_SATA (0xB << 0) 155 #define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_MASK (0x1f << 0) 156 #define CCM_PMU_MISC1_LVDSCLK1_OBEN (1 << 10) 157 #define CCM_PMU_MISC1_LVDSCLK1_IBEN (1 << 12) 158 159 #define HCLK_FREQ 24000000 160 #define PLL3_80M 80000000 161 162 #define HREAD4(sc, reg) \ 163 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 164 #define HWRITE4(sc, reg, val) \ 165 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 166 #define HSET4(sc, reg, bits) \ 167 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 168 #define HCLR4(sc, reg, bits) \ 169 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 170 171 struct imxccm_gate { 172 uint8_t reg; 173 uint8_t pos; 174 uint8_t parent; 175 }; 176 177 #include "imxccm_clocks.h" 178 179 struct imxccm_softc { 180 struct device sc_dev; 181 bus_space_tag_t sc_iot; 182 bus_space_handle_t sc_ioh; 183 int sc_node; 184 185 struct imxccm_gate *sc_gates; 186 int sc_ngates; 187 struct clock_device sc_cd; 188 }; 189 190 enum clocks { 191 /* OSC */ 192 OSC, /* 24 MHz OSC */ 193 194 /* PLLs */ 195 ARM_PLL1, /* ARM core PLL */ 196 SYS_PLL2, /* System PLL: 528 MHz */ 197 USB1_PLL3, /* OTG USB PLL: 480 MHz */ 198 USB2_PLL, /* Host USB PLL: 480 MHz */ 199 AUD_PLL4, /* Audio PLL */ 200 VID_PLL5, /* Video PLL */ 201 ENET_PLL6, /* ENET PLL */ 202 MLB_PLL, /* MLB PLL */ 203 204 /* SYS_PLL2 PFDs */ 205 SYS_PLL2_PFD0, /* 352 MHz */ 206 SYS_PLL2_PFD1, /* 594 MHz */ 207 SYS_PLL2_PFD2, /* 396 MHz */ 208 209 /* USB1_PLL3 PFDs */ 210 USB1_PLL3_PFD0, /* 720 MHz */ 211 USB1_PLL3_PFD1, /* 540 MHz */ 212 USB1_PLL3_PFD2, /* 508.2 MHz */ 213 USB1_PLL3_PFD3, /* 454.7 MHz */ 214 }; 215 216 int imxccm_match(struct device *, void *, void *); 217 void imxccm_attach(struct device *parent, struct device *self, void *args); 218 219 struct cfattach imxccm_ca = { 220 sizeof (struct imxccm_softc), imxccm_match, imxccm_attach 221 }; 222 223 struct cfdriver imxccm_cd = { 224 NULL, "imxccm", DV_DULL 225 }; 226 227 uint32_t imxccm_decode_pll(struct imxccm_softc *, enum clocks, uint32_t); 228 uint32_t imxccm_get_pll2_pfd(struct imxccm_softc *, unsigned int); 229 uint32_t imxccm_get_pll3_pfd(struct imxccm_softc *, unsigned int); 230 uint32_t imxccm_get_armclk(struct imxccm_softc *); 231 void imxccm_armclk_set_parent(struct imxccm_softc *, enum clocks); 232 uint32_t imxccm_get_usdhx(struct imxccm_softc *, int x); 233 uint32_t imxccm_get_periphclk(struct imxccm_softc *); 234 uint32_t imxccm_get_ahbclk(struct imxccm_softc *); 235 uint32_t imxccm_get_ipgclk(struct imxccm_softc *); 236 uint32_t imxccm_get_ipg_perclk(struct imxccm_softc *); 237 uint32_t imxccm_get_uartclk(struct imxccm_softc *); 238 void imxccm_enable(void *, uint32_t *, int); 239 uint32_t imxccm_get_frequency(void *, uint32_t *); 240 void imxccm_enable_pll_usb1(struct imxccm_softc *); 241 void imxccm_enable_pll_usb2(struct imxccm_softc *); 242 void imxccm_enable_pll_enet(struct imxccm_softc *); 243 void imxccm_enable_enet(struct imxccm_softc *); 244 void imxccm_enable_sata(struct imxccm_softc *); 245 246 int 247 imxccm_match(struct device *parent, void *match, void *aux) 248 { 249 struct fdt_attach_args *faa = aux; 250 251 return (OF_is_compatible(faa->fa_node, "fsl,imx6q-ccm") || 252 OF_is_compatible(faa->fa_node, "fsl,imx6sl-ccm") || 253 OF_is_compatible(faa->fa_node, "fsl,imx6sx-ccm") || 254 OF_is_compatible(faa->fa_node, "fsl,imx6ul-ccm")); 255 } 256 257 void 258 imxccm_attach(struct device *parent, struct device *self, void *aux) 259 { 260 struct imxccm_softc *sc = (struct imxccm_softc *)self; 261 struct fdt_attach_args *faa = aux; 262 263 KASSERT(faa->fa_nreg >= 1); 264 265 sc->sc_node = faa->fa_node; 266 sc->sc_iot = faa->fa_iot; 267 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 268 faa->fa_reg[0].size + 0x1000, 0, &sc->sc_ioh)) 269 panic("%s: bus_space_map failed!", __func__); 270 271 if (OF_is_compatible(sc->sc_node, "fsl,imx6ul-ccm")) { 272 sc->sc_gates = imx6ul_gates; 273 sc->sc_ngates = nitems(imx6ul_gates); 274 } else { 275 sc->sc_gates = imx6_gates; 276 sc->sc_ngates = nitems(imx6_gates); 277 } 278 279 printf(": imx6 rev 1.%d CPU freq: %d MHz", 280 HREAD4(sc, CCM_ANALOG_DIGPROG) & CCM_ANALOG_DIGPROG_MINOR_MASK, 281 imxccm_get_armclk(sc) / 1000000); 282 283 printf("\n"); 284 285 sc->sc_cd.cd_node = faa->fa_node; 286 sc->sc_cd.cd_cookie = sc; 287 sc->sc_cd.cd_enable = imxccm_enable; 288 sc->sc_cd.cd_get_frequency = imxccm_get_frequency; 289 clock_register(&sc->sc_cd); 290 } 291 292 uint32_t 293 imxccm_decode_pll(struct imxccm_softc *sc, enum clocks pll, uint32_t freq) 294 { 295 uint32_t div; 296 297 switch (pll) { 298 case ARM_PLL1: 299 if (HREAD4(sc, CCM_ANALOG_PLL_ARM) 300 & CCM_ANALOG_PLL_ARM_BYPASS) 301 return freq; 302 div = HREAD4(sc, CCM_ANALOG_PLL_ARM) 303 & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK; 304 return (freq * div) / 2; 305 case SYS_PLL2: 306 div = HREAD4(sc, CCM_ANALOG_PLL_SYS) 307 & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK; 308 return freq * (20 + (div << 1)); 309 case USB1_PLL3: 310 div = HREAD4(sc, CCM_ANALOG_PLL_USB2) 311 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK; 312 return freq * (20 + (div << 1)); 313 default: 314 return 0; 315 } 316 } 317 318 uint32_t 319 imxccm_get_pll2_pfd(struct imxccm_softc *sc, unsigned int pfd) 320 { 321 return imxccm_decode_pll(sc, SYS_PLL2, HCLK_FREQ) * 18ULL 322 / CCM_ANALOG_PFD_528_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_528), pfd); 323 } 324 325 uint32_t 326 imxccm_get_pll3_pfd(struct imxccm_softc *sc, unsigned int pfd) 327 { 328 return imxccm_decode_pll(sc, USB1_PLL3, HCLK_FREQ) * 18ULL 329 / CCM_ANALOG_PFD_480_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_480), pfd); 330 } 331 332 uint32_t 333 imxccm_get_armclk(struct imxccm_softc *sc) 334 { 335 uint32_t ccsr = HREAD4(sc, CCM_CCSR); 336 337 if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL)) 338 return imxccm_decode_pll(sc, ARM_PLL1, HCLK_FREQ); 339 else if (ccsr & CCM_CCSR_STEP_SEL) 340 return imxccm_get_pll2_pfd(sc, 2); 341 else 342 return HCLK_FREQ; 343 } 344 345 void 346 imxccm_armclk_set_parent(struct imxccm_softc *sc, enum clocks clock) 347 { 348 switch (clock) 349 { 350 case ARM_PLL1: 351 /* jump onto pll1 */ 352 HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 353 /* put step clk on OSC, power saving */ 354 HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 355 break; 356 case OSC: 357 /* put step clk on OSC */ 358 HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 359 /* jump onto step clk */ 360 HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 361 break; 362 case SYS_PLL2_PFD2: 363 /* put step clk on pll2-pfd2 400 MHz */ 364 HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 365 /* jump onto step clk */ 366 HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 367 break; 368 default: 369 panic("%s: parent not possible for arm clk", __func__); 370 } 371 } 372 373 unsigned int 374 imxccm_get_usdhx(struct imxccm_softc *sc, int x) 375 { 376 uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1); 377 uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1); 378 uint32_t podf, clkroot; 379 380 // Odd bitsetting. Damn you. 381 if (x == 1) 382 podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK); 383 else 384 podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK); 385 386 if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x))) 387 clkroot = imxccm_get_pll2_pfd(sc, 0); // 352 MHz 388 else 389 clkroot = imxccm_get_pll2_pfd(sc, 2); // 396 MHz 390 391 return clkroot / (podf + 1); 392 } 393 394 uint32_t 395 imxccm_get_uartclk(struct imxccm_softc *sc) 396 { 397 uint32_t clkroot = PLL3_80M; 398 uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK; 399 400 return clkroot / (podf + 1); 401 } 402 403 uint32_t 404 imxccm_get_periphclk(struct imxccm_softc *sc) 405 { 406 if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT) 407 & CCM_CBCDR_PERIPH_CLK_SEL_MASK) { 408 switch((HREAD4(sc, CCM_CBCMR) 409 >> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) { 410 case 0: 411 return imxccm_decode_pll(sc, USB1_PLL3, HCLK_FREQ); 412 case 1: 413 case 2: 414 return HCLK_FREQ; 415 default: 416 return 0; 417 } 418 419 } else { 420 switch((HREAD4(sc, CCM_CBCMR) 421 >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) { 422 default: 423 case 0: 424 return imxccm_decode_pll(sc, SYS_PLL2, HCLK_FREQ); 425 case 1: 426 return imxccm_get_pll2_pfd(sc, 2); // 396 MHz 427 case 2: 428 return imxccm_get_pll2_pfd(sc, 0); // 352 MHz 429 case 3: 430 return imxccm_get_pll2_pfd(sc, 2) / 2; // 198 MHz 431 } 432 } 433 } 434 435 uint32_t 436 imxccm_get_ahbclk(struct imxccm_softc *sc) 437 { 438 uint32_t ahb_podf; 439 440 ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT) 441 & CCM_CBCDR_AHB_PODF_MASK; 442 return imxccm_get_periphclk(sc) / (ahb_podf + 1); 443 } 444 445 uint32_t 446 imxccm_get_ipgclk(struct imxccm_softc *sc) 447 { 448 uint32_t ipg_podf; 449 450 ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT) 451 & CCM_CBCDR_IPG_PODF_MASK; 452 return imxccm_get_ahbclk(sc) / (ipg_podf + 1); 453 } 454 455 uint32_t 456 imxccm_get_ipg_perclk(struct imxccm_softc *sc) 457 { 458 uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1); 459 uint32_t freq, ipg_podf; 460 461 if (sc->sc_gates == imx6ul_gates && 462 cscmr1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) 463 freq = HCLK_FREQ; 464 else 465 freq = imxccm_get_ipgclk(sc); 466 467 ipg_podf = cscmr1 & CCM_CSCMR1_PERCLK_CLK_PODF_MASK; 468 469 return freq / (ipg_podf + 1); 470 } 471 472 void 473 imxccm_enable(void *cookie, uint32_t *cells, int on) 474 { 475 struct imxccm_softc *sc = cookie; 476 uint32_t idx = cells[0]; 477 uint8_t reg, pos; 478 479 /* Dummy clock. */ 480 if (idx == 0) 481 return; 482 483 if (sc->sc_gates == imx6_gates) { 484 switch (idx) { 485 case IMX6_CLK_USBPHY1: 486 imxccm_enable_pll_usb1(sc); 487 return; 488 case IMX6_CLK_USBPHY2: 489 imxccm_enable_pll_usb2(sc); 490 return; 491 case IMX6_CLK_SATA_REF_100: 492 imxccm_enable_sata(sc); 493 return; 494 case IMX6_CLK_ENET_REF: 495 imxccm_enable_enet(sc); 496 return; 497 default: 498 break; 499 } 500 } 501 502 if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) { 503 printf("%s: 0x%08x\n", __func__, idx); 504 return; 505 } 506 507 reg = sc->sc_gates[idx].reg; 508 pos = sc->sc_gates[idx].pos; 509 510 if (on) 511 HSET4(sc, reg, 0x3 << (2 * pos)); 512 else 513 HCLR4(sc, reg, 0x3 << (2 * pos)); 514 } 515 516 uint32_t 517 imxccm_get_frequency(void *cookie, uint32_t *cells) 518 { 519 struct imxccm_softc *sc = cookie; 520 uint32_t idx = cells[0]; 521 uint32_t parent; 522 523 /* Dummy clock. */ 524 if (idx == 0) 525 return 0; 526 527 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 528 parent = sc->sc_gates[idx].parent; 529 return imxccm_get_frequency(sc, &parent); 530 } 531 532 if (sc->sc_gates == imx6ul_gates) { 533 switch (idx) { 534 case IMX6UL_CLK_ARM: 535 return imxccm_get_armclk(sc); 536 case IMX6UL_CLK_IPG: 537 return imxccm_get_ipgclk(sc); 538 case IMX6UL_CLK_PERCLK: 539 return imxccm_get_ipg_perclk(sc); 540 case IMX6UL_CLK_UART1_SERIAL: 541 return imxccm_get_uartclk(sc); 542 case IMX6UL_CLK_USDHC1: 543 case IMX6UL_CLK_USDHC2: 544 return imxccm_get_usdhx(sc, idx - IMX6UL_CLK_USDHC1 + 1); 545 } 546 } else { 547 switch (idx) { 548 case IMX6_CLK_AHB: 549 return imxccm_get_ahbclk(sc); 550 case IMX6_CLK_ARM: 551 return imxccm_get_armclk(sc); 552 case IMX6_CLK_IPG: 553 return imxccm_get_ipgclk(sc); 554 case IMX6_CLK_IPG_PER: 555 return imxccm_get_ipg_perclk(sc); 556 case IMX6_CLK_UART_SERIAL: 557 return imxccm_get_uartclk(sc); 558 case IMX6_CLK_USDHC1: 559 case IMX6_CLK_USDHC2: 560 case IMX6_CLK_USDHC3: 561 case IMX6_CLK_USDHC4: 562 return imxccm_get_usdhx(sc, idx - IMX6_CLK_USDHC1 + 1); 563 } 564 } 565 566 printf("%s: 0x%08x\n", __func__, idx); 567 return 0; 568 } 569 570 void 571 imxccm_enable_pll_enet(struct imxccm_softc *sc) 572 { 573 if (HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_ENABLE) 574 return; 575 576 HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_POWERDOWN); 577 578 HSET4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_ENABLE); 579 580 while(!(HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK)); 581 582 HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS); 583 } 584 585 void 586 imxccm_enable_enet(struct imxccm_softc *sc) 587 { 588 imxccm_enable_pll_enet(sc); 589 HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_DIV_125M); 590 } 591 592 void 593 imxccm_enable_sata(struct imxccm_softc *sc) 594 { 595 imxccm_enable_pll_enet(sc); 596 HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_100M_SATA); 597 } 598 599 void 600 imxccm_enable_pll_usb1(struct imxccm_softc *sc) 601 { 602 HWRITE4(sc, CCM_ANALOG_PLL_USB1_CLR, CCM_ANALOG_PLL_USB1_BYPASS); 603 604 HWRITE4(sc, CCM_ANALOG_PLL_USB1_SET, 605 CCM_ANALOG_PLL_USB1_ENABLE 606 | CCM_ANALOG_PLL_USB1_POWER 607 | CCM_ANALOG_PLL_USB1_EN_USB_CLKS); 608 } 609 610 void 611 imxccm_enable_pll_usb2(struct imxccm_softc *sc) 612 { 613 HWRITE4(sc, CCM_ANALOG_PLL_USB2_CLR, CCM_ANALOG_PLL_USB2_BYPASS); 614 615 HWRITE4(sc, CCM_ANALOG_PLL_USB2_SET, 616 CCM_ANALOG_PLL_USB2_ENABLE 617 | CCM_ANALOG_PLL_USB2_POWER 618 | CCM_ANALOG_PLL_USB2_EN_USB_CLKS); 619 } 620