1 /* $OpenBSD: imxccm.c,v 1.11 2018/08/20 16:48:03 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/ofw_misc.h> 35 #include <dev/ofw/ofw_regulator.h> 36 #include <dev/ofw/fdt.h> 37 38 #include <dev/fdt/imxanatopvar.h> 39 40 /* registers */ 41 #define CCM_CCR 0x00 42 #define CCM_CCDR 0x04 43 #define CCM_CSR 0x08 44 #define CCM_CCSR 0x0c 45 #define CCM_CACRR 0x10 46 #define CCM_CBCDR 0x14 47 #define CCM_CBCMR 0x18 48 #define CCM_CSCMR1 0x1c 49 #define CCM_CSCMR2 0x20 50 #define CCM_CSCDR1 0x24 51 #define CCM_CS1CDR 0x28 52 #define CCM_CS2CDR 0x2c 53 #define CCM_CDCDR 0x30 54 #define CCM_CHSCCDR 0x34 55 #define CCM_CSCDR2 0x38 56 #define CCM_CSCDR3 0x3c 57 #define CCM_CSCDR4 0x40 58 #define CCM_CDHIPR 0x48 59 #define CCM_CDCR 0x4c 60 #define CCM_CTOR 0x50 61 #define CCM_CLPCR 0x54 62 #define CCM_CISR 0x58 63 #define CCM_CIMR 0x5c 64 #define CCM_CCOSR 0x60 65 #define CCM_CGPR 0x64 66 #define CCM_CCGR0 0x68 67 #define CCM_CCGR1 0x6c 68 #define CCM_CCGR2 0x70 69 #define CCM_CCGR3 0x74 70 #define CCM_CCGR4 0x78 71 #define CCM_CCGR5 0x7c 72 #define CCM_CCGR6 0x80 73 #define CCM_CCGR7 0x84 74 #define CCM_CMEOR 0x88 75 76 /* bits and bytes */ 77 #define CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0) 78 #define CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1) 79 #define CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) 80 #define CCM_CCSR_STEP_SEL (1 << 8) 81 #define CCM_CBCDR_IPG_PODF_SHIFT 8 82 #define CCM_CBCDR_IPG_PODF_MASK 0x3 83 #define CCM_CBCDR_AHB_PODF_SHIFT 10 84 #define CCM_CBCDR_AHB_PODF_MASK 0x7 85 #define CCM_CBCDR_PERIPH_CLK_SEL_SHIFT 25 86 #define CCM_CBCDR_PERIPH_CLK_SEL_MASK 0x1 87 #define CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT 12 88 #define CCM_CBCMR_PERIPH_CLK2_SEL_MASK 0x3 89 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT 18 90 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK 0x3 91 #define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x) ((x) + 15) 92 #define CCM_CSCDR1_USDHCx_CLK_SEL_MASK 0x1 93 #define CCM_CSCDR1_USDHCx_PODF_MASK 0x7 94 #define CCM_CSCDR1_UART_PODF_MASK 0x7 95 #define CCM_CSCDR2_ECSPI_PODF_SHIFT 19 96 #define CCM_CSCDR2_ECSPI_PODF_MASK 0x7 97 #define CCM_CCGR1_ENET (3 << 10) 98 #define CCM_CCGR4_125M_PCIE (3 << 0) 99 #define CCM_CCGR5_100M_SATA (3 << 4) 100 #define CCM_CSCMR1_PERCLK_CLK_PODF_MASK 0x1f 101 #define CCM_CSCMR1_PERCLK_CLK_SEL_MASK (1 << 6) 102 103 /* Analog registers */ 104 #define CCM_ANALOG_PLL_USB1 0x0010 105 #define CCM_ANALOG_PLL_USB1_SET 0x0014 106 #define CCM_ANALOG_PLL_USB1_CLR 0x0018 107 #define CCM_ANALOG_PLL_USB1_LOCK (1U << 31) 108 #define CCM_ANALOG_PLL_USB1_BYPASS (1 << 16) 109 #define CCM_ANALOG_PLL_USB1_ENABLE (1 << 13) 110 #define CCM_ANALOG_PLL_USB1_POWER (1 << 12) 111 #define CCM_ANALOG_PLL_USB1_EN_USB_CLKS (1 << 6) 112 #define CCM_ANALOG_PLL_USB2 0x0020 113 #define CCM_ANALOG_PLL_USB2_SET 0x0024 114 #define CCM_ANALOG_PLL_USB2_CLR 0x0028 115 #define CCM_ANALOG_PLL_USB2_LOCK (1U << 31) 116 #define CCM_ANALOG_PLL_USB2_BYPASS (1 << 16) 117 #define CCM_ANALOG_PLL_USB2_ENABLE (1 << 13) 118 #define CCM_ANALOG_PLL_USB2_POWER (1 << 12) 119 #define CCM_ANALOG_PLL_USB2_EN_USB_CLKS (1 << 6) 120 #define CCM_ANALOG_PLL_ENET 0x00e0 121 #define CCM_ANALOG_PLL_ENET_SET 0x00e4 122 #define CCM_ANALOG_PLL_ENET_CLR 0x00e8 123 #define CCM_ANALOG_PLL_ENET_LOCK (1U << 31) 124 #define CCM_ANALOG_PLL_ENET_ENABLE_100M (1 << 20) /* i.MX6 */ 125 #define CCM_ANALOG_PLL_ENET_BYPASS (1 << 16) 126 #define CCM_ANALOG_PLL_ENET_ENABLE (1 << 13) /* i.MX6 */ 127 #define CCM_ANALOG_PLL_ENET_POWERDOWN (1 << 12) /* i.MX6 */ 128 #define CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ (1 << 10) /* i.MX7 */ 129 130 /* Frac PLL */ 131 #define CCM_FRAC_IMX8M_ARM_PLL0 0x28 132 #define CCM_FRAC_IMX8M_ARM_PLL1 0x2c 133 #define CCM_FRAC_PLL_LOCK (1 << 31) 134 #define CCM_FRAC_PLL_ENABLE (1 << 21) 135 #define CCM_FRAC_PLL_POWERDOWN (1 << 19) 136 #define CCM_FRAC_PLL_REFCLK_SEL_SHIFT 16 137 #define CCM_FRAC_PLL_REFCLK_SEL_MASK 0x3 138 #define CCM_FRAC_PLL_LOCK_SEL (1 << 15) 139 #define CCM_FRAC_PLL_BYPASS (1 << 14) 140 #define CCM_FRAC_PLL_COUNTCLK_SEL (1 << 13) 141 #define CCM_FRAC_PLL_NEWDIV_VAL (1 << 12) 142 #define CCM_FRAC_PLL_NEWDIV_ACK (1 << 11) 143 #define CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT 5 144 #define CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK 0x3f 145 #define CCM_FRAC_PLL_OUTPUT_DIV_VAL_SHIFT 0 146 #define CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK 0x1f 147 #define CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT 7 148 #define CCM_FRAC_PLL_FRAC_DIV_CTL_MASK 0x1ffffff 149 #define CCM_FRAC_PLL_INT_DIV_CTL_SHIFT 0 150 #define CCM_FRAC_PLL_INT_DIV_CTL_MASK 0x7f 151 #define CCM_FRAC_PLL_DENOM (1 << 24) 152 #define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG 0x78 153 #define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT 20 154 #define CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK 0x7 155 156 #define HCLK_FREQ 24000000 157 #define PLL3_60M 60000000 158 #define PLL3_80M 80000000 159 160 #define HREAD4(sc, reg) \ 161 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 162 #define HWRITE4(sc, reg, val) \ 163 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 164 #define HSET4(sc, reg, bits) \ 165 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 166 #define HCLR4(sc, reg, bits) \ 167 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 168 169 struct imxccm_gate { 170 uint16_t reg; 171 uint8_t pos; 172 uint16_t parent; 173 }; 174 175 struct imxccm_divider { 176 uint16_t reg; 177 uint16_t shift; 178 uint16_t mask; 179 uint16_t parent; 180 uint16_t fixed; 181 }; 182 183 struct imxccm_mux { 184 uint16_t reg; 185 uint16_t shift; 186 uint16_t mask; 187 }; 188 189 #include "imxccm_clocks.h" 190 191 struct imxccm_softc { 192 struct device sc_dev; 193 bus_space_tag_t sc_iot; 194 bus_space_handle_t sc_ioh; 195 int sc_node; 196 uint32_t sc_phandle; 197 198 struct regmap *sc_anatop; 199 200 struct imxccm_gate *sc_gates; 201 int sc_ngates; 202 struct imxccm_divider *sc_divs; 203 int sc_ndivs; 204 struct imxccm_mux *sc_muxs; 205 int sc_nmuxs; 206 struct clock_device sc_cd; 207 }; 208 209 int imxccm_match(struct device *, void *, void *); 210 void imxccm_attach(struct device *parent, struct device *self, void *args); 211 212 struct cfattach imxccm_ca = { 213 sizeof (struct imxccm_softc), imxccm_match, imxccm_attach 214 }; 215 216 struct cfdriver imxccm_cd = { 217 NULL, "imxccm", DV_DULL 218 }; 219 220 uint32_t imxccm_get_armclk(struct imxccm_softc *); 221 void imxccm_armclk_set_parent(struct imxccm_softc *, enum imxanatop_clocks); 222 uint32_t imxccm_get_usdhx(struct imxccm_softc *, int x); 223 uint32_t imxccm_get_periphclk(struct imxccm_softc *); 224 uint32_t imxccm_get_ahbclk(struct imxccm_softc *); 225 uint32_t imxccm_get_ipgclk(struct imxccm_softc *); 226 uint32_t imxccm_get_ipg_perclk(struct imxccm_softc *); 227 uint32_t imxccm_get_uartclk(struct imxccm_softc *); 228 uint32_t imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t); 229 uint32_t imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t); 230 uint32_t imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t); 231 uint32_t imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t); 232 uint32_t imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t); 233 uint32_t imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t); 234 void imxccm_enable(void *, uint32_t *, int); 235 uint32_t imxccm_get_frequency(void *, uint32_t *); 236 int imxccm_set_frequency(void *, uint32_t *, uint32_t); 237 int imxccm_set_parent(void *, uint32_t *, uint32_t *); 238 239 int 240 imxccm_match(struct device *parent, void *match, void *aux) 241 { 242 struct fdt_attach_args *faa = aux; 243 244 return (OF_is_compatible(faa->fa_node, "fsl,imx6q-ccm") || 245 OF_is_compatible(faa->fa_node, "fsl,imx6sl-ccm") || 246 OF_is_compatible(faa->fa_node, "fsl,imx6sx-ccm") || 247 OF_is_compatible(faa->fa_node, "fsl,imx6ul-ccm") || 248 OF_is_compatible(faa->fa_node, "fsl,imx7d-ccm") || 249 OF_is_compatible(faa->fa_node, "fsl,imx8mq-ccm")); 250 } 251 252 void 253 imxccm_attach(struct device *parent, struct device *self, void *aux) 254 { 255 struct imxccm_softc *sc = (struct imxccm_softc *)self; 256 struct fdt_attach_args *faa = aux; 257 258 KASSERT(faa->fa_nreg >= 1); 259 260 sc->sc_node = faa->fa_node; 261 sc->sc_iot = faa->fa_iot; 262 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 263 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 264 panic("%s: bus_space_map failed!", __func__); 265 266 sc->sc_phandle = OF_getpropint(sc->sc_node, "phandle", 0); 267 268 if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-ccm")) { 269 sc->sc_anatop = regmap_bycompatible("fsl,imx8mq-anatop"); 270 KASSERT(sc->sc_anatop != NULL); 271 sc->sc_gates = imx8mq_gates; 272 sc->sc_ngates = nitems(imx8mq_gates); 273 sc->sc_divs = imx8mq_divs; 274 sc->sc_ndivs = nitems(imx8mq_divs); 275 sc->sc_muxs = imx8mq_muxs; 276 sc->sc_nmuxs = nitems(imx8mq_muxs); 277 } else if (OF_is_compatible(sc->sc_node, "fsl,imx7d-ccm")) { 278 sc->sc_gates = imx7d_gates; 279 sc->sc_ngates = nitems(imx7d_gates); 280 sc->sc_divs = imx7d_divs; 281 sc->sc_ndivs = nitems(imx7d_divs); 282 sc->sc_muxs = imx7d_muxs; 283 sc->sc_nmuxs = nitems(imx7d_muxs); 284 } else if (OF_is_compatible(sc->sc_node, "fsl,imx6ul-ccm")) { 285 sc->sc_gates = imx6ul_gates; 286 sc->sc_ngates = nitems(imx6ul_gates); 287 } else { 288 sc->sc_gates = imx6_gates; 289 sc->sc_ngates = nitems(imx6_gates); 290 } 291 292 printf("\n"); 293 294 sc->sc_cd.cd_node = faa->fa_node; 295 sc->sc_cd.cd_cookie = sc; 296 sc->sc_cd.cd_enable = imxccm_enable; 297 sc->sc_cd.cd_get_frequency = imxccm_get_frequency; 298 sc->sc_cd.cd_set_frequency = imxccm_set_frequency; 299 sc->sc_cd.cd_set_parent = imxccm_set_parent; 300 clock_register(&sc->sc_cd); 301 } 302 303 uint32_t 304 imxccm_get_armclk(struct imxccm_softc *sc) 305 { 306 uint32_t ccsr = HREAD4(sc, CCM_CCSR); 307 308 if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL)) 309 return imxanatop_decode_pll(ARM_PLL1, HCLK_FREQ); 310 else if (ccsr & CCM_CCSR_STEP_SEL) 311 return imxanatop_get_pll2_pfd(2); 312 else 313 return HCLK_FREQ; 314 } 315 316 void 317 imxccm_armclk_set_parent(struct imxccm_softc *sc, enum imxanatop_clocks clock) 318 { 319 switch (clock) 320 { 321 case ARM_PLL1: 322 /* jump onto pll1 */ 323 HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 324 /* put step clk on OSC, power saving */ 325 HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 326 break; 327 case OSC: 328 /* put step clk on OSC */ 329 HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 330 /* jump onto step clk */ 331 HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 332 break; 333 case SYS_PLL2_PFD2: 334 /* put step clk on pll2-pfd2 400 MHz */ 335 HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL); 336 /* jump onto step clk */ 337 HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL); 338 break; 339 default: 340 panic("%s: parent not possible for arm clk", __func__); 341 } 342 } 343 344 uint32_t 345 imxccm_get_ecspiclk(struct imxccm_softc *sc) 346 { 347 uint32_t clkroot = PLL3_60M; 348 uint32_t podf = HREAD4(sc, CCM_CSCDR2); 349 350 podf >>= CCM_CSCDR2_ECSPI_PODF_SHIFT; 351 podf &= CCM_CSCDR2_ECSPI_PODF_MASK; 352 353 return clkroot / (podf + 1); 354 } 355 356 unsigned int 357 imxccm_get_usdhx(struct imxccm_softc *sc, int x) 358 { 359 uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1); 360 uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1); 361 uint32_t podf, clkroot; 362 363 // Odd bitsetting. Damn you. 364 if (x == 1) 365 podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK); 366 else 367 podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK); 368 369 if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x))) 370 clkroot = imxanatop_get_pll2_pfd(0); // 352 MHz 371 else 372 clkroot = imxanatop_get_pll2_pfd(2); // 396 MHz 373 374 return clkroot / (podf + 1); 375 } 376 377 uint32_t 378 imxccm_get_uartclk(struct imxccm_softc *sc) 379 { 380 uint32_t clkroot = PLL3_80M; 381 uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK; 382 383 return clkroot / (podf + 1); 384 } 385 386 uint32_t 387 imxccm_get_periphclk(struct imxccm_softc *sc) 388 { 389 if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT) 390 & CCM_CBCDR_PERIPH_CLK_SEL_MASK) { 391 switch((HREAD4(sc, CCM_CBCMR) 392 >> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) { 393 case 0: 394 return imxanatop_decode_pll(USB1_PLL3, HCLK_FREQ); 395 case 1: 396 case 2: 397 return HCLK_FREQ; 398 default: 399 return 0; 400 } 401 402 } else { 403 switch((HREAD4(sc, CCM_CBCMR) 404 >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) { 405 default: 406 case 0: 407 return imxanatop_decode_pll(SYS_PLL2, HCLK_FREQ); 408 case 1: 409 return imxanatop_get_pll2_pfd(2); // 396 MHz 410 case 2: 411 return imxanatop_get_pll2_pfd(0); // 352 MHz 412 case 3: 413 return imxanatop_get_pll2_pfd(2) / 2; // 198 MHz 414 } 415 } 416 } 417 418 uint32_t 419 imxccm_get_ahbclk(struct imxccm_softc *sc) 420 { 421 uint32_t ahb_podf; 422 423 ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT) 424 & CCM_CBCDR_AHB_PODF_MASK; 425 return imxccm_get_periphclk(sc) / (ahb_podf + 1); 426 } 427 428 uint32_t 429 imxccm_get_ipgclk(struct imxccm_softc *sc) 430 { 431 uint32_t ipg_podf; 432 433 ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT) 434 & CCM_CBCDR_IPG_PODF_MASK; 435 return imxccm_get_ahbclk(sc) / (ipg_podf + 1); 436 } 437 438 uint32_t 439 imxccm_get_ipg_perclk(struct imxccm_softc *sc) 440 { 441 uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1); 442 uint32_t freq, ipg_podf; 443 444 if (sc->sc_gates == imx6ul_gates && 445 cscmr1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) 446 freq = HCLK_FREQ; 447 else 448 freq = imxccm_get_ipgclk(sc); 449 450 ipg_podf = cscmr1 & CCM_CSCMR1_PERCLK_CLK_PODF_MASK; 451 452 return freq / (ipg_podf + 1); 453 } 454 455 void 456 imxccm_imx6_enable_pll_enet(struct imxccm_softc *sc, int on) 457 { 458 KASSERT(on); 459 460 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR, 461 CCM_ANALOG_PLL_ENET_POWERDOWN); 462 463 /* Wait for the PLL to lock. */ 464 while ((regmap_read_4(sc->sc_anatop, 465 CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK) == 0) 466 ; 467 468 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_CLR, 469 CCM_ANALOG_PLL_ENET_BYPASS); 470 } 471 472 void 473 imxccm_imx6_enable_pll_usb1(struct imxccm_softc *sc, int on) 474 { 475 KASSERT(on); 476 477 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET, 478 CCM_ANALOG_PLL_USB1_POWER); 479 480 /* Wait for the PLL to lock. */ 481 while ((regmap_read_4(sc->sc_anatop, 482 CCM_ANALOG_PLL_USB1) & CCM_ANALOG_PLL_USB1_LOCK) == 0) 483 ; 484 485 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_CLR, 486 CCM_ANALOG_PLL_USB1_BYPASS); 487 } 488 489 void 490 imxccm_imx6_enable_pll_usb2(struct imxccm_softc *sc, int on) 491 { 492 KASSERT(on); 493 494 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET, 495 CCM_ANALOG_PLL_USB2_POWER); 496 497 /* Wait for the PLL to lock. */ 498 while ((regmap_read_4(sc->sc_anatop, 499 CCM_ANALOG_PLL_USB2) & CCM_ANALOG_PLL_USB2_LOCK) == 0) 500 ; 501 502 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_CLR, 503 CCM_ANALOG_PLL_USB2_BYPASS); 504 } 505 506 uint32_t 507 imxccm_imx7d_enet(struct imxccm_softc *sc, uint32_t idx) 508 { 509 uint32_t mux; 510 511 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 512 return 0; 513 514 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 515 mux >>= sc->sc_muxs[idx].shift; 516 mux &= sc->sc_muxs[idx].mask; 517 518 switch (mux) { 519 case 0: 520 return clock_get_frequency(sc->sc_node, "osc"); 521 case 7: 522 return 392000000; /* pll_sys_pfd4_clk XXX not fixed */ 523 default: 524 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 525 return 0; 526 } 527 } 528 529 uint32_t 530 imxccm_imx7d_i2c(struct imxccm_softc *sc, uint32_t idx) 531 { 532 uint32_t mux; 533 534 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 535 return 0; 536 537 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 538 mux >>= sc->sc_muxs[idx].shift; 539 mux &= sc->sc_muxs[idx].mask; 540 541 switch (mux) { 542 case 0: 543 return clock_get_frequency(sc->sc_node, "osc"); 544 case 1: 545 return 120000000; /* pll_sys_main_120m_clk */ 546 default: 547 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 548 return 0; 549 } 550 } 551 552 uint32_t 553 imxccm_imx7d_uart(struct imxccm_softc *sc, uint32_t idx) 554 { 555 uint32_t mux; 556 557 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 558 return 0; 559 560 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 561 mux >>= sc->sc_muxs[idx].shift; 562 mux &= sc->sc_muxs[idx].mask; 563 564 switch (mux) { 565 case 0: 566 return clock_get_frequency(sc->sc_node, "osc"); 567 default: 568 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 569 return 0; 570 } 571 } 572 573 uint32_t 574 imxccm_imx7d_usdhc(struct imxccm_softc *sc, uint32_t idx) 575 { 576 uint32_t mux; 577 578 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 579 return 0; 580 581 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 582 mux >>= sc->sc_muxs[idx].shift; 583 mux &= sc->sc_muxs[idx].mask; 584 585 switch (mux) { 586 case 0: 587 return clock_get_frequency(sc->sc_node, "osc"); 588 case 1: 589 return 392000000; /* pll_sys_pfd0_392m_clk */ 590 default: 591 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 592 return 0; 593 } 594 } 595 596 uint32_t 597 imxccm_imx8mq_ecspi(struct imxccm_softc *sc, uint32_t idx) 598 { 599 uint32_t mux; 600 601 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 602 return 0; 603 604 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 605 mux >>= sc->sc_muxs[idx].shift; 606 mux &= sc->sc_muxs[idx].mask; 607 608 switch (mux) { 609 case 0: 610 return clock_get_frequency(sc->sc_node, "osc_25m"); 611 case 1: 612 return 200 * 1000 * 1000; /* sys2_pll_200m */ 613 default: 614 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 615 return 0; 616 } 617 } 618 619 uint32_t 620 imxccm_imx8mq_enet(struct imxccm_softc *sc, uint32_t idx) 621 { 622 uint32_t mux; 623 624 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 625 return 0; 626 627 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 628 mux >>= sc->sc_muxs[idx].shift; 629 mux &= sc->sc_muxs[idx].mask; 630 631 switch (mux) { 632 case 0: 633 return clock_get_frequency(sc->sc_node, "osc_25m"); 634 case 1: 635 return 266 * 1000 * 1000; /* sys1_pll_266m */ 636 default: 637 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 638 return 0; 639 } 640 } 641 642 uint32_t 643 imxccm_imx8mq_i2c(struct imxccm_softc *sc, uint32_t idx) 644 { 645 uint32_t mux; 646 647 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 648 return 0; 649 650 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 651 mux >>= sc->sc_muxs[idx].shift; 652 mux &= sc->sc_muxs[idx].mask; 653 654 switch (mux) { 655 case 0: 656 return clock_get_frequency(sc->sc_node, "osc_25m"); 657 default: 658 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 659 return 0; 660 } 661 } 662 663 uint32_t 664 imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t idx) 665 { 666 uint32_t mux; 667 668 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 669 return 0; 670 671 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 672 mux >>= sc->sc_muxs[idx].shift; 673 mux &= sc->sc_muxs[idx].mask; 674 675 switch (mux) { 676 case 0: 677 return clock_get_frequency(sc->sc_node, "osc_25m"); 678 default: 679 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 680 return 0; 681 } 682 } 683 684 uint32_t 685 imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t idx) 686 { 687 uint32_t mux; 688 689 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 690 return 0; 691 692 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 693 mux >>= sc->sc_muxs[idx].shift; 694 mux &= sc->sc_muxs[idx].mask; 695 696 switch (mux) { 697 case 0: 698 return clock_get_frequency(sc->sc_node, "osc_25m"); 699 case 1: 700 return 400 * 1000 * 1000; /* sys1_pll_400m */ 701 default: 702 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 703 return 0; 704 } 705 } 706 707 uint32_t 708 imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t idx) 709 { 710 uint32_t mux; 711 712 if (idx >= sc->sc_nmuxs || sc->sc_muxs[idx].reg == 0) 713 return 0; 714 715 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 716 mux >>= sc->sc_muxs[idx].shift; 717 mux &= sc->sc_muxs[idx].mask; 718 719 switch (mux) { 720 case 0: 721 return clock_get_frequency(sc->sc_node, "osc_25m"); 722 case 1: 723 if (idx == IMX8MQ_CLK_USB_CORE_REF_SRC || 724 idx == IMX8MQ_CLK_USB_PHY_REF_SRC) 725 return 100 * 1000 * 1000; /* sys1_pll_100m */ 726 if (idx == IMX8MQ_CLK_USB_BUS_SRC) 727 return 500 * 1000 * 1000; /* sys2_pll_500m */ 728 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 729 return 0; 730 default: 731 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 732 return 0; 733 } 734 } 735 736 uint32_t 737 imxccm_imx8mq_get_pll(struct imxccm_softc *sc, uint32_t idx) 738 { 739 uint32_t divr_val, divq_val, divf_val; 740 uint32_t divff, divfi; 741 uint32_t pllout_div; 742 uint32_t pll0, pll1; 743 uint32_t freq; 744 uint32_t mux; 745 746 pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG); 747 748 switch (idx) { 749 case IMX8MQ_ARM_PLL: 750 pll0 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL0); 751 pll1 = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_ARM_PLL1); 752 pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT; 753 pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK; 754 break; 755 default: 756 printf("%s: 0x%08x\n", __func__, idx); 757 return 0; 758 } 759 760 if (pll0 & CCM_FRAC_PLL_POWERDOWN) 761 return 0; 762 763 if ((pll0 & CCM_FRAC_PLL_ENABLE) == 0) 764 return 0; 765 766 mux = (pll0 >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) & 767 CCM_FRAC_PLL_REFCLK_SEL_MASK; 768 switch (mux) { 769 case 0: 770 freq = clock_get_frequency(sc->sc_node, "osc_25m"); 771 break; 772 case 1: 773 case 2: 774 freq = clock_get_frequency(sc->sc_node, "osc_27m"); 775 break; 776 default: 777 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 778 return 0; 779 } 780 781 if (pll0 & CCM_FRAC_PLL_BYPASS) 782 return freq; 783 784 divr_val = (pll0 >> CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT) & 785 CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK; 786 divq_val = pll0 & CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK; 787 divff = (pll1 >> CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT) & 788 CCM_FRAC_PLL_FRAC_DIV_CTL_MASK; 789 divfi = pll1 & CCM_FRAC_PLL_INT_DIV_CTL_MASK; 790 divf_val = 1 + divfi + divff / CCM_FRAC_PLL_DENOM; 791 792 freq = freq / (divr_val + 1) * 8 * divf_val / ((divq_val + 1) * 2); 793 return freq / (pllout_div + 1); 794 } 795 796 int 797 imxccm_imx8mq_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq) 798 { 799 uint64_t divff, divfi, divr; 800 uint32_t pllout_div; 801 uint32_t pll0, pll1; 802 uint32_t mux, reg; 803 uint64_t pfreq; 804 int i; 805 806 pllout_div = regmap_read_4(sc->sc_anatop, CCM_FRAC_IMX8M_PLLOUT_DIV_CFG); 807 808 switch (idx) { 809 case IMX8MQ_ARM_PLL: 810 pll0 = CCM_FRAC_IMX8M_ARM_PLL0; 811 pll1 = CCM_FRAC_IMX8M_ARM_PLL1; 812 pllout_div >>= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_SHIFT; 813 pllout_div &= CCM_FRAC_IMX8M_PLLOUT_DIV_CFG_ARM_MASK; 814 /* XXX: Assume fixed divider to ease math. */ 815 KASSERT(pllout_div == 0); 816 divr = 5; 817 break; 818 default: 819 printf("%s: 0x%08x\n", __func__, idx); 820 return -1; 821 } 822 823 reg = regmap_read_4(sc->sc_anatop, pll0); 824 mux = (reg >> CCM_FRAC_PLL_REFCLK_SEL_SHIFT) & 825 CCM_FRAC_PLL_REFCLK_SEL_MASK; 826 switch (mux) { 827 case 0: 828 pfreq = clock_get_frequency(sc->sc_node, "osc_25m"); 829 break; 830 case 1: 831 case 2: 832 pfreq = clock_get_frequency(sc->sc_node, "osc_27m"); 833 break; 834 default: 835 printf("%s: 0x%08x 0x%08x\n", __func__, idx, mux); 836 return -1; 837 } 838 839 /* Frac divider follows the PLL */ 840 freq *= divr; 841 842 /* PLL calculation */ 843 freq *= 2; 844 pfreq *= 8; 845 divfi = freq / pfreq; 846 divff = (uint64_t)(freq - divfi * pfreq); 847 divff = (divff * CCM_FRAC_PLL_DENOM) / pfreq; 848 849 reg = regmap_read_4(sc->sc_anatop, pll1); 850 reg &= ~(CCM_FRAC_PLL_FRAC_DIV_CTL_MASK << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT); 851 reg |= divff << CCM_FRAC_PLL_FRAC_DIV_CTL_SHIFT; 852 reg &= ~(CCM_FRAC_PLL_INT_DIV_CTL_MASK << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT); 853 reg |= (divfi - 1) << CCM_FRAC_PLL_INT_DIV_CTL_SHIFT; 854 regmap_write_4(sc->sc_anatop, pll1, reg); 855 856 reg = regmap_read_4(sc->sc_anatop, pll0); 857 reg &= ~CCM_FRAC_PLL_OUTPUT_DIV_VAL_MASK; 858 reg &= ~(CCM_FRAC_PLL_REFCLK_DIV_VAL_MASK << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT); 859 reg |= (divr - 1) << CCM_FRAC_PLL_REFCLK_DIV_VAL_SHIFT; 860 regmap_write_4(sc->sc_anatop, pll0, reg); 861 862 reg = regmap_read_4(sc->sc_anatop, pll0); 863 reg |= CCM_FRAC_PLL_NEWDIV_VAL; 864 regmap_write_4(sc->sc_anatop, pll0, reg); 865 866 for (i = 0; i < 5000; i++) { 867 reg = regmap_read_4(sc->sc_anatop, pll0); 868 if (reg & CCM_FRAC_PLL_BYPASS) 869 break; 870 if (reg & CCM_FRAC_PLL_POWERDOWN) 871 break; 872 if (reg & CCM_FRAC_PLL_NEWDIV_ACK) 873 break; 874 delay(10); 875 } 876 if (i == 5000) 877 printf("%s: timeout\n", __func__); 878 879 reg = regmap_read_4(sc->sc_anatop, pll0); 880 reg &= ~CCM_FRAC_PLL_NEWDIV_VAL; 881 regmap_write_4(sc->sc_anatop, pll0, reg); 882 883 return 0; 884 } 885 886 void 887 imxccm_enable_parent(struct imxccm_softc *sc, uint32_t parent, int on) 888 { 889 if (on) 890 imxccm_enable(sc, &parent, on); 891 } 892 893 void 894 imxccm_enable(void *cookie, uint32_t *cells, int on) 895 { 896 struct imxccm_softc *sc = cookie; 897 uint32_t idx = cells[0], parent; 898 uint16_t reg; 899 uint8_t pos; 900 901 /* Dummy clock. */ 902 if (idx == 0) 903 return; 904 905 if (sc->sc_gates == imx7d_gates) { 906 if (sc->sc_anatop == NULL) { 907 sc->sc_anatop = regmap_bycompatible("fsl,imx7d-anatop"); 908 KASSERT(sc->sc_anatop); 909 } 910 911 switch (idx) { 912 case IMX7D_PLL_ENET_MAIN_125M_CLK: 913 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_ENET_SET, 914 CCM_ANALOG_PLL_ENET_ENABLE_CLK_125MHZ); 915 return; 916 default: 917 break; 918 } 919 } else if (sc->sc_gates == imx6_gates) { 920 if (sc->sc_anatop == NULL) { 921 sc->sc_anatop = regmap_bycompatible("fsl,imx6q-anatop"); 922 KASSERT(sc->sc_anatop); 923 } 924 925 switch (idx) { 926 case IMX6_CLK_PLL3: 927 imxccm_imx6_enable_pll_usb1(sc, on); 928 return; 929 case IMX6_CLK_PLL6: 930 imxccm_imx6_enable_pll_enet(sc, on); 931 return; 932 case IMX6_CLK_PLL7: 933 imxccm_imx6_enable_pll_usb2(sc, on); 934 return; 935 case IMX6_CLK_PLL3_USB_OTG: 936 imxccm_enable_parent(sc, IMX6_CLK_PLL3, on); 937 regmap_write_4(sc->sc_anatop, 938 on ? CCM_ANALOG_PLL_USB1_SET : CCM_ANALOG_PLL_USB1_CLR, 939 CCM_ANALOG_PLL_USB1_ENABLE); 940 return; 941 case IMX6_CLK_PLL6_ENET: 942 imxccm_enable_parent(sc, IMX6_CLK_PLL6, on); 943 regmap_write_4(sc->sc_anatop, 944 on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR, 945 CCM_ANALOG_PLL_ENET_ENABLE); 946 return; 947 case IMX6_CLK_PLL7_USB_HOST: 948 imxccm_enable_parent(sc, IMX6_CLK_PLL7, on); 949 regmap_write_4(sc->sc_anatop, 950 on ? CCM_ANALOG_PLL_USB2_SET : CCM_ANALOG_PLL_USB2_CLR, 951 CCM_ANALOG_PLL_USB2_ENABLE); 952 return; 953 case IMX6_CLK_USBPHY1: 954 /* PLL outputs should alwas be on. */ 955 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB1_SET, 956 CCM_ANALOG_PLL_USB1_EN_USB_CLKS); 957 imxccm_enable_parent(sc, IMX6_CLK_PLL3_USB_OTG, on); 958 return; 959 case IMX6_CLK_USBPHY2: 960 /* PLL outputs should alwas be on. */ 961 regmap_write_4(sc->sc_anatop, CCM_ANALOG_PLL_USB2_SET, 962 CCM_ANALOG_PLL_USB2_EN_USB_CLKS); 963 imxccm_enable_parent(sc, IMX6_CLK_PLL7_USB_HOST, on); 964 return; 965 case IMX6_CLK_SATA_REF_100: 966 imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on); 967 regmap_write_4(sc->sc_anatop, 968 on ? CCM_ANALOG_PLL_ENET_SET : CCM_ANALOG_PLL_ENET_CLR, 969 CCM_ANALOG_PLL_ENET_ENABLE_100M); 970 return; 971 case IMX6_CLK_ENET_REF: 972 imxccm_enable_parent(sc, IMX6_CLK_PLL6_ENET, on); 973 return; 974 case IMX6_CLK_IPG: 975 case IMX6_CLK_IPG_PER: 976 case IMX6_CLK_ECSPI_ROOT: 977 /* always on */ 978 return; 979 default: 980 break; 981 } 982 } 983 984 if (on) { 985 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 986 parent = sc->sc_gates[idx].parent; 987 imxccm_enable(sc, &parent, on); 988 } 989 990 if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) { 991 parent = sc->sc_divs[idx].parent; 992 imxccm_enable(sc, &parent, on); 993 } 994 } 995 996 if ((idx < sc->sc_ndivs && sc->sc_divs[idx].reg != 0) || 997 (idx < sc->sc_nmuxs && sc->sc_muxs[idx].reg != 0)) 998 return; 999 1000 if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) { 1001 printf("%s: 0x%08x\n", __func__, idx); 1002 return; 1003 } 1004 1005 reg = sc->sc_gates[idx].reg; 1006 pos = sc->sc_gates[idx].pos; 1007 1008 if (on) 1009 HSET4(sc, reg, 0x3 << (2 * pos)); 1010 else 1011 HCLR4(sc, reg, 0x3 << (2 * pos)); 1012 } 1013 1014 uint32_t 1015 imxccm_get_frequency(void *cookie, uint32_t *cells) 1016 { 1017 struct imxccm_softc *sc = cookie; 1018 uint32_t idx = cells[0]; 1019 uint32_t div, parent; 1020 1021 /* Dummy clock. */ 1022 if (idx == 0) 1023 return 0; 1024 1025 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 1026 parent = sc->sc_gates[idx].parent; 1027 return imxccm_get_frequency(sc, &parent); 1028 } 1029 1030 if (idx < sc->sc_ndivs && sc->sc_divs[idx].parent) { 1031 div = HREAD4(sc, sc->sc_divs[idx].reg); 1032 div = div >> sc->sc_divs[idx].shift; 1033 div = div & sc->sc_divs[idx].mask; 1034 parent = sc->sc_divs[idx].parent; 1035 return imxccm_get_frequency(sc, &parent) / (div + 1); 1036 } 1037 1038 if (sc->sc_gates == imx8mq_gates) { 1039 switch (idx) { 1040 case IMX8MQ_ARM_PLL: 1041 return imxccm_imx8mq_get_pll(sc, idx); 1042 case IMX8MQ_CLK_A53_SRC: 1043 parent = IMX8MQ_ARM_PLL; 1044 return imxccm_get_frequency(sc, &parent); 1045 case IMX8MQ_CLK_ENET_AXI_SRC: 1046 return imxccm_imx8mq_enet(sc, idx); 1047 case IMX8MQ_CLK_I2C1_SRC: 1048 case IMX8MQ_CLK_I2C2_SRC: 1049 case IMX8MQ_CLK_I2C3_SRC: 1050 case IMX8MQ_CLK_I2C4_SRC: 1051 return imxccm_imx8mq_i2c(sc, idx); 1052 case IMX8MQ_CLK_UART1_SRC: 1053 case IMX8MQ_CLK_UART2_SRC: 1054 case IMX8MQ_CLK_UART3_SRC: 1055 case IMX8MQ_CLK_UART4_SRC: 1056 return imxccm_imx8mq_uart(sc, idx); 1057 case IMX8MQ_CLK_USDHC1_SRC: 1058 case IMX8MQ_CLK_USDHC2_SRC: 1059 return imxccm_imx8mq_usdhc(sc, idx); 1060 case IMX8MQ_CLK_USB_BUS_SRC: 1061 case IMX8MQ_CLK_USB_CORE_REF_SRC: 1062 case IMX8MQ_CLK_USB_PHY_REF_SRC: 1063 return imxccm_imx8mq_usb(sc, idx); 1064 case IMX8MQ_CLK_ECSPI1_SRC: 1065 case IMX8MQ_CLK_ECSPI2_SRC: 1066 case IMX8MQ_CLK_ECSPI3_SRC: 1067 return imxccm_imx8mq_ecspi(sc, idx); 1068 } 1069 } else if (sc->sc_gates == imx7d_gates) { 1070 switch (idx) { 1071 case IMX7D_ENET_AXI_ROOT_SRC: 1072 return imxccm_imx7d_enet(sc, idx); 1073 case IMX7D_I2C1_ROOT_SRC: 1074 case IMX7D_I2C2_ROOT_SRC: 1075 case IMX7D_I2C3_ROOT_SRC: 1076 case IMX7D_I2C4_ROOT_SRC: 1077 return imxccm_imx7d_i2c(sc, idx); 1078 case IMX7D_UART1_ROOT_SRC: 1079 case IMX7D_UART2_ROOT_SRC: 1080 case IMX7D_UART3_ROOT_SRC: 1081 case IMX7D_UART4_ROOT_SRC: 1082 case IMX7D_UART5_ROOT_SRC: 1083 case IMX7D_UART6_ROOT_SRC: 1084 case IMX7D_UART7_ROOT_SRC: 1085 return imxccm_imx7d_uart(sc, idx); 1086 case IMX7D_USDHC1_ROOT_SRC: 1087 case IMX7D_USDHC2_ROOT_SRC: 1088 case IMX7D_USDHC3_ROOT_SRC: 1089 return imxccm_imx7d_usdhc(sc, idx); 1090 } 1091 } else if (sc->sc_gates == imx6ul_gates) { 1092 switch (idx) { 1093 case IMX6UL_CLK_ARM: 1094 return imxccm_get_armclk(sc); 1095 case IMX6UL_CLK_IPG: 1096 return imxccm_get_ipgclk(sc); 1097 case IMX6UL_CLK_PERCLK: 1098 return imxccm_get_ipg_perclk(sc); 1099 case IMX6UL_CLK_UART1_SERIAL: 1100 return imxccm_get_uartclk(sc); 1101 case IMX6UL_CLK_USDHC1: 1102 case IMX6UL_CLK_USDHC2: 1103 return imxccm_get_usdhx(sc, idx - IMX6UL_CLK_USDHC1 + 1); 1104 } 1105 } else if (sc->sc_gates == imx6_gates) { 1106 switch (idx) { 1107 case IMX6_CLK_AHB: 1108 return imxccm_get_ahbclk(sc); 1109 case IMX6_CLK_ARM: 1110 return imxccm_get_armclk(sc); 1111 case IMX6_CLK_IPG: 1112 return imxccm_get_ipgclk(sc); 1113 case IMX6_CLK_IPG_PER: 1114 return imxccm_get_ipg_perclk(sc); 1115 case IMX6_CLK_ECSPI_ROOT: 1116 return imxccm_get_ecspiclk(sc); 1117 case IMX6_CLK_UART_SERIAL: 1118 return imxccm_get_uartclk(sc); 1119 case IMX6_CLK_USDHC1: 1120 case IMX6_CLK_USDHC2: 1121 case IMX6_CLK_USDHC3: 1122 case IMX6_CLK_USDHC4: 1123 return imxccm_get_usdhx(sc, idx - IMX6_CLK_USDHC1 + 1); 1124 } 1125 } 1126 1127 printf("%s: 0x%08x\n", __func__, idx); 1128 return 0; 1129 } 1130 1131 int 1132 imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 1133 { 1134 struct imxccm_softc *sc = cookie; 1135 uint32_t idx = cells[0]; 1136 uint32_t reg, div, parent, parent_freq; 1137 uint32_t pcells[2]; 1138 int ret; 1139 1140 if (sc->sc_divs == imx8mq_divs) { 1141 switch (idx) { 1142 case IMX8MQ_CLK_A53_DIV: 1143 parent = IMX8MQ_CLK_A53_SRC; 1144 return imxccm_set_frequency(cookie, &parent, freq); 1145 case IMX8MQ_CLK_A53_SRC: 1146 pcells[0] = sc->sc_phandle; 1147 pcells[1] = IMX8MQ_SYS1_PLL_800M; 1148 ret = imxccm_set_parent(cookie, &idx, pcells); 1149 if (ret) 1150 return ret; 1151 ret = imxccm_imx8mq_set_pll(sc, IMX8MQ_ARM_PLL, freq); 1152 pcells[0] = sc->sc_phandle; 1153 pcells[1] = IMX8MQ_ARM_PLL_OUT; 1154 imxccm_set_parent(cookie, &idx, pcells); 1155 return ret; 1156 case IMX8MQ_CLK_USB_BUS_SRC: 1157 case IMX8MQ_CLK_USB_CORE_REF_SRC: 1158 case IMX8MQ_CLK_USB_PHY_REF_SRC: 1159 if (imxccm_get_frequency(sc, cells) != freq) 1160 break; 1161 return 0; 1162 case IMX8MQ_CLK_USDHC1_DIV: 1163 parent = sc->sc_divs[idx].parent; 1164 if (imxccm_get_frequency(sc, &parent) != freq) 1165 break; 1166 imxccm_enable(cookie, &parent, 1); 1167 reg = HREAD4(sc, sc->sc_divs[idx].reg); 1168 reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift); 1169 reg |= (0x0 << sc->sc_divs[idx].shift); 1170 HWRITE4(sc, sc->sc_divs[idx].reg, reg); 1171 return 0; 1172 } 1173 } else if (sc->sc_divs == imx7d_divs) { 1174 switch (idx) { 1175 case IMX7D_USDHC1_ROOT_CLK: 1176 case IMX7D_USDHC2_ROOT_CLK: 1177 case IMX7D_USDHC3_ROOT_CLK: 1178 parent = sc->sc_gates[idx].parent; 1179 return imxccm_set_frequency(sc, &parent, freq); 1180 case IMX7D_USDHC1_ROOT_DIV: 1181 case IMX7D_USDHC2_ROOT_DIV: 1182 case IMX7D_USDHC3_ROOT_DIV: 1183 parent = sc->sc_divs[idx].parent; 1184 parent_freq = imxccm_get_frequency(sc, &parent); 1185 div = 0; 1186 while (parent_freq / (div + 1) > freq) 1187 div++; 1188 reg = HREAD4(sc, sc->sc_divs[idx].reg); 1189 reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift); 1190 reg |= (div << sc->sc_divs[idx].shift); 1191 HWRITE4(sc, sc->sc_divs[idx].reg, reg); 1192 return 0; 1193 } 1194 } 1195 1196 printf("%s: 0x%08x %x\n", __func__, idx, freq); 1197 return -1; 1198 } 1199 1200 int 1201 imxccm_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 1202 { 1203 struct imxccm_softc *sc = cookie; 1204 uint32_t idx = cells[0]; 1205 uint32_t pidx; 1206 uint32_t mux; 1207 1208 if (pcells[0] != sc->sc_phandle) { 1209 printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, pcells[0]); 1210 return -1; 1211 } 1212 1213 pidx = pcells[1]; 1214 1215 if (sc->sc_muxs == imx8mq_muxs) { 1216 switch (idx) { 1217 case IMX8MQ_CLK_A53_SRC: 1218 if (pidx != IMX8MQ_ARM_PLL_OUT && 1219 pidx != IMX8MQ_SYS1_PLL_800M) 1220 break; 1221 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 1222 mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift); 1223 if (pidx == IMX8MQ_ARM_PLL_OUT) 1224 mux |= (0x1 << sc->sc_muxs[idx].shift); 1225 if (pidx == IMX8MQ_SYS1_PLL_800M) 1226 mux |= (0x4 << sc->sc_muxs[idx].shift); 1227 HWRITE4(sc, sc->sc_muxs[idx].reg, mux); 1228 return 0; 1229 case IMX8MQ_CLK_USB_BUS_SRC: 1230 if (pidx != IMX8MQ_SYS2_PLL_500M) 1231 break; 1232 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 1233 mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift); 1234 mux |= (0x1 << sc->sc_muxs[idx].shift); 1235 HWRITE4(sc, sc->sc_muxs[idx].reg, mux); 1236 return 0; 1237 case IMX8MQ_CLK_USB_CORE_REF_SRC: 1238 case IMX8MQ_CLK_USB_PHY_REF_SRC: 1239 if (pidx != IMX8MQ_SYS1_PLL_100M) 1240 break; 1241 mux = HREAD4(sc, sc->sc_muxs[idx].reg); 1242 mux &= ~(sc->sc_muxs[idx].mask << sc->sc_muxs[idx].shift); 1243 mux |= (0x1 << sc->sc_muxs[idx].shift); 1244 HWRITE4(sc, sc->sc_muxs[idx].reg, mux); 1245 return 0; 1246 } 1247 } 1248 1249 printf("%s: 0x%08x 0x%08x\n", __func__, idx, pidx); 1250 return -1; 1251 } 1252