1 /* $OpenBSD: sxiccmu.c,v 1.7 2017/09/08 05:36:52 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2013 Artturi Alm 5 * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/malloc.h> 24 #include <sys/time.h> 25 #include <sys/device.h> 26 27 #include <machine/bus.h> 28 #include <machine/fdt.h> 29 #include <machine/intr.h> 30 31 #include <dev/fdt/sunxireg.h> 32 33 #include <dev/ofw/openfirm.h> 34 #include <dev/ofw/ofw_clock.h> 35 #include <dev/ofw/fdt.h> 36 37 #ifdef DEBUG_CCMU 38 #define DPRINTF(x) do { printf x; } while (0) 39 #else 40 #define DPRINTF(x) 41 #endif 42 43 struct sxiccmu_ccu_bit { 44 uint16_t reg; 45 uint8_t bit; 46 uint8_t parent; 47 }; 48 49 #include "sxiccmu_clocks.h" 50 51 struct sxiccmu_softc { 52 struct device sc_dev; 53 bus_space_tag_t sc_iot; 54 bus_space_handle_t sc_ioh; 55 int sc_node; 56 57 struct sxiccmu_ccu_bit *sc_gates; 58 int sc_ngates; 59 struct clock_device sc_cd; 60 61 struct sxiccmu_ccu_bit *sc_resets; 62 int sc_nresets; 63 struct reset_device sc_rd; 64 65 uint32_t (*sc_get_frequency)(struct sxiccmu_softc *, 66 uint32_t); 67 int (*sc_set_frequency)(struct sxiccmu_softc *, 68 uint32_t, uint32_t); 69 }; 70 71 int sxiccmu_match(struct device *, void *, void *); 72 void sxiccmu_attach(struct device *, struct device *, void *); 73 74 struct cfattach sxiccmu_ca = { 75 sizeof (struct sxiccmu_softc), sxiccmu_match, sxiccmu_attach 76 }; 77 78 struct cfdriver sxiccmu_cd = { 79 NULL, "sxiccmu", DV_DULL 80 }; 81 82 void sxiccmu_attach_clock(struct sxiccmu_softc *, int); 83 84 uint32_t sxiccmu_ccu_get_frequency(void *, uint32_t *); 85 int sxiccmu_ccu_set_frequency(void *, uint32_t *, uint32_t); 86 void sxiccmu_ccu_enable(void *, uint32_t *, int); 87 void sxiccmu_ccu_reset(void *, uint32_t *, int); 88 89 uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t); 90 int sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 91 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t); 92 int sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 93 94 int 95 sxiccmu_match(struct device *parent, void *match, void *aux) 96 { 97 struct fdt_attach_args *faa = aux; 98 99 if (faa->fa_node == OF_finddevice("/clocks")) { 100 int node = OF_parent(faa->fa_node); 101 102 return (OF_is_compatible(node, "allwinner,sun4i-a10") || 103 OF_is_compatible(node, "allwinner,sun5i-a10s") || 104 OF_is_compatible(node, "allwinner,sun5i-r8") || 105 OF_is_compatible(node, "allwinner,sun7i-a20") || 106 OF_is_compatible(node, "allwinner,sun8i-h3") || 107 OF_is_compatible(node, "allwinner,sun9i-a80") || 108 OF_is_compatible(node, "allwinner,sun50i-a64") || 109 OF_is_compatible(node, "allwinner,sun50i-h5")); 110 } 111 112 return (OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-ccu") || 113 OF_is_compatible(faa->fa_node, "allwinner,sun50i-a64-ccu") || 114 OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-ccu")); 115 } 116 117 void 118 sxiccmu_attach(struct device *parent, struct device *self, void *aux) 119 { 120 struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self; 121 struct fdt_attach_args *faa = aux; 122 int node; 123 124 sc->sc_node = faa->fa_node; 125 sc->sc_iot = faa->fa_iot; 126 if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot, 127 faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh)) 128 panic("%s: bus_space_map failed!", __func__); 129 130 printf("\n"); 131 132 if (OF_is_compatible(sc->sc_node, "allwinner,sun50i-a64-ccu")) { 133 KASSERT(faa->fa_nreg > 0); 134 sc->sc_gates = sun50i_a64_gates; 135 sc->sc_ngates = nitems(sun50i_a64_gates); 136 sc->sc_resets = sun50i_a64_resets; 137 sc->sc_nresets = nitems(sun50i_a64_resets); 138 sc->sc_get_frequency = sxiccmu_a64_get_frequency; 139 sc->sc_set_frequency = sxiccmu_a64_set_frequency; 140 } else if (OF_is_compatible(sc->sc_node, "allwinner,sun8i-h3-ccu") || 141 OF_is_compatible(sc->sc_node, "allwinner,sun50i-h5-ccu")) { 142 KASSERT(faa->fa_nreg > 0); 143 sc->sc_gates = sun8i_h3_gates; 144 sc->sc_ngates = nitems(sun8i_h3_gates); 145 sc->sc_resets = sun8i_h3_resets; 146 sc->sc_nresets = nitems(sun8i_h3_resets); 147 sc->sc_get_frequency = sxiccmu_h3_get_frequency; 148 sc->sc_set_frequency = sxiccmu_h3_set_frequency; 149 } else { 150 for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) 151 sxiccmu_attach_clock(sc, node); 152 } 153 154 if (sc->sc_gates) { 155 sc->sc_cd.cd_node = sc->sc_node; 156 sc->sc_cd.cd_cookie = sc; 157 sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency; 158 sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency; 159 sc->sc_cd.cd_enable = sxiccmu_ccu_enable; 160 clock_register(&sc->sc_cd); 161 } 162 163 if (sc->sc_resets) { 164 sc->sc_rd.rd_node = sc->sc_node; 165 sc->sc_rd.rd_cookie = sc; 166 sc->sc_rd.rd_reset = sxiccmu_ccu_reset; 167 reset_register(&sc->sc_rd); 168 } 169 } 170 171 /* 172 * Classic device trees for the Allwinner SoCs have basically a clock 173 * node per register of the clock control unit. Attaching a separate 174 * driver to each of them would be crazy, so we handle them here. 175 */ 176 177 struct sxiccmu_clock { 178 int sc_node; 179 bus_space_tag_t sc_iot; 180 bus_space_handle_t sc_ioh; 181 182 struct clock_device sc_cd; 183 struct reset_device sc_rd; 184 }; 185 186 struct sxiccmu_device { 187 const char *compat; 188 uint32_t (*get_frequency)(void *, uint32_t *); 189 int (*set_frequency)(void *, uint32_t *, uint32_t); 190 void (*enable)(void *, uint32_t *, int); 191 void (*reset)(void *, uint32_t *, int); 192 }; 193 194 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *); 195 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *); 196 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *); 197 void sxiccmu_pll6_enable(void *, uint32_t *, int); 198 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *); 199 int sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t); 200 int sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t); 201 void sxiccmu_mmc_enable(void *, uint32_t *, int); 202 void sxiccmu_gate_enable(void *, uint32_t *, int); 203 void sxiccmu_reset(void *, uint32_t *, int); 204 205 struct sxiccmu_device sxiccmu_devices[] = { 206 { 207 .compat = "allwinner,sun4i-a10-osc-clk", 208 .get_frequency = sxiccmu_osc_get_frequency, 209 }, 210 { 211 .compat = "allwinner,sun4i-a10-pll6-clk", 212 .get_frequency = sxiccmu_pll6_get_frequency, 213 .enable = sxiccmu_pll6_enable 214 }, 215 { 216 .compat = "allwinner,sun4i-a10-apb1-clk", 217 .get_frequency = sxiccmu_apb1_get_frequency, 218 }, 219 { 220 .compat = "allwinner,sun4i-a10-ahb-gates-clk", 221 .get_frequency = sxiccmu_gen_get_frequency, 222 .enable = sxiccmu_gate_enable 223 }, 224 { 225 .compat = "allwinner,sun4i-a10-apb0-gates-clk", 226 .get_frequency = sxiccmu_gen_get_frequency, 227 .enable = sxiccmu_gate_enable 228 }, 229 { 230 .compat = "allwinner,sun4i-a10-apb1-gates-clk", 231 .get_frequency = sxiccmu_gen_get_frequency, 232 .enable = sxiccmu_gate_enable 233 }, 234 { 235 .compat = "allwinner,sun4i-a10-mmc-clk", 236 .set_frequency = sxiccmu_mmc_set_frequency, 237 .enable = sxiccmu_mmc_enable 238 }, 239 { 240 .compat = "allwinner,sun4i-a10-usb-clk", 241 .get_frequency = sxiccmu_gen_get_frequency, 242 .enable = sxiccmu_gate_enable, 243 .reset = sxiccmu_reset 244 }, 245 { 246 .compat = "allwinner,sun5i-a10s-ahb-gates-clk", 247 .get_frequency = sxiccmu_gen_get_frequency, 248 .enable = sxiccmu_gate_enable 249 }, 250 { 251 .compat = "allwinner,sun5i-a10s-apb0-gates-clk", 252 .get_frequency = sxiccmu_gen_get_frequency, 253 .enable = sxiccmu_gate_enable 254 }, 255 { 256 .compat = "allwinner,sun5i-a10s-apb1-gates-clk", 257 .get_frequency = sxiccmu_gen_get_frequency, 258 .enable = sxiccmu_gate_enable 259 }, 260 { 261 .compat = "allwinner,sun5i-a13-ahb-gates-clk", 262 .get_frequency = sxiccmu_gen_get_frequency, 263 .enable = sxiccmu_gate_enable 264 }, 265 { 266 .compat = "allwinner,sun5i-a13-apb0-gates-clk", 267 .get_frequency = sxiccmu_gen_get_frequency, 268 .enable = sxiccmu_gate_enable 269 }, 270 { 271 .compat = "allwinner,sun5i-a13-apb1-gates-clk", 272 .get_frequency = sxiccmu_gen_get_frequency, 273 .enable = sxiccmu_gate_enable 274 }, 275 { 276 .compat = "allwinner,sun5i-a13-usb-clk", 277 .get_frequency = sxiccmu_gen_get_frequency, 278 .enable = sxiccmu_gate_enable, 279 .reset = sxiccmu_reset 280 }, 281 { 282 .compat = "allwinner,sun6i-a31-ahb1-reset", 283 .reset = sxiccmu_reset 284 }, 285 { 286 .compat = "allwinner,sun6i-a31-clock-reset", 287 .reset = sxiccmu_reset 288 }, 289 { 290 .compat = "allwinner,sun7i-a20-ahb-gates-clk", 291 .get_frequency = sxiccmu_gen_get_frequency, 292 .enable = sxiccmu_gate_enable 293 }, 294 { 295 .compat = "allwinner,sun7i-a20-apb0-gates-clk", 296 .get_frequency = sxiccmu_gen_get_frequency, 297 .enable = sxiccmu_gate_enable 298 }, 299 { 300 .compat = "allwinner,sun7i-a20-apb1-gates-clk", 301 .get_frequency = sxiccmu_gen_get_frequency, 302 .enable = sxiccmu_gate_enable 303 }, 304 { 305 .compat = "allwinner,sun7i-a20-gmac-clk", 306 .set_frequency = sxiccmu_gmac_set_frequency 307 }, 308 { 309 .compat = "allwinner,sun8i-h3-apb0-gates-clk", 310 .get_frequency = sxiccmu_gen_get_frequency, 311 .enable = sxiccmu_gate_enable 312 }, 313 { 314 .compat = "allwinner,sun9i-a80-apb1-clk", 315 .get_frequency = sxiccmu_apb1_get_frequency, 316 }, 317 { 318 .compat = "allwinner,sun9i-a80-ahb0-gates-clk", 319 .get_frequency = sxiccmu_gen_get_frequency, 320 .enable = sxiccmu_gate_enable 321 }, 322 { 323 .compat = "allwinner,sun9i-a80-ahb1-gates-clk", 324 .get_frequency = sxiccmu_gen_get_frequency, 325 .enable = sxiccmu_gate_enable 326 }, 327 { 328 .compat = "allwinner,sun9i-a80-ahb2-gates-clk", 329 .get_frequency = sxiccmu_gen_get_frequency, 330 .enable = sxiccmu_gate_enable 331 }, 332 { 333 .compat = "allwinner,sun9i-a80-apb0-gates-clk", 334 .get_frequency = sxiccmu_gen_get_frequency, 335 .enable = sxiccmu_gate_enable 336 }, 337 { 338 .compat = "allwinner,sun9i-a80-apb1-gates-clk", 339 .get_frequency = sxiccmu_gen_get_frequency, 340 .enable = sxiccmu_gate_enable 341 }, 342 { 343 .compat = "allwinner,sun9i-a80-apbs-gates-clk", 344 .get_frequency = sxiccmu_gen_get_frequency, 345 .enable = sxiccmu_gate_enable 346 }, 347 { 348 .compat = "allwinner,sun9i-a80-mmc-clk", 349 .set_frequency = sxiccmu_mmc_set_frequency, 350 .enable = sxiccmu_mmc_enable 351 }, 352 { 353 .compat = "allwinner,sun9i-a80-usb-mod-clk", 354 .get_frequency = sxiccmu_gen_get_frequency, 355 .enable = sxiccmu_gate_enable, 356 .reset = sxiccmu_reset 357 }, 358 { 359 .compat = "allwinner,sun9i-a80-usb-phy-clk", 360 .get_frequency = sxiccmu_gen_get_frequency, 361 .enable = sxiccmu_gate_enable, 362 .reset = sxiccmu_reset 363 }, 364 }; 365 366 void 367 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node) 368 { 369 struct sxiccmu_clock *clock; 370 uint32_t reg[2]; 371 int i; 372 373 for (i = 0; i < nitems(sxiccmu_devices); i++) 374 if (OF_is_compatible(node, sxiccmu_devices[i].compat)) 375 break; 376 if (i == nitems(sxiccmu_devices)) 377 return; 378 379 clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK); 380 clock->sc_node = node; 381 382 if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) { 383 clock->sc_iot = sc->sc_iot; 384 if (bus_space_map(clock->sc_iot, reg[0], reg[1], 0, 385 &clock->sc_ioh)) { 386 printf("%s: can't map registers", sc->sc_dev.dv_xname); 387 free(clock, M_DEVBUF, sizeof(*clock)); 388 return; 389 } 390 } 391 392 clock->sc_cd.cd_node = node; 393 clock->sc_cd.cd_cookie = clock; 394 clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency; 395 clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency; 396 clock->sc_cd.cd_enable = sxiccmu_devices[i].enable; 397 clock_register(&clock->sc_cd); 398 399 if (sxiccmu_devices[i].reset) { 400 clock->sc_rd.rd_node = node; 401 clock->sc_rd.rd_cookie = clock; 402 clock->sc_rd.rd_reset = sxiccmu_devices[i].reset; 403 reset_register(&clock->sc_rd); 404 } 405 } 406 407 /* 408 * A "generic" function that simply gets the clock frequency from the 409 * parent clock. Useful for clock gating devices that don't scale 410 * their clocks. 411 */ 412 uint32_t 413 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells) 414 { 415 struct sxiccmu_clock *sc = cookie; 416 417 return clock_get_frequency(sc->sc_node, NULL); 418 } 419 420 uint32_t 421 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells) 422 { 423 struct sxiccmu_clock *sc = cookie; 424 425 return OF_getpropint(sc->sc_node, "clock-frequency", 24000000); 426 } 427 428 #define CCU_PLL6_ENABLE (1U << 31) 429 #define CCU_PLL6_BYPASS_EN (1U << 30) 430 #define CCU_PLL6_SATA_CLK_EN (1U << 14) 431 #define CCU_PLL6_FACTOR_N(x) (((x) >> 8) & 0x1f) 432 #define CCU_PLL6_FACTOR_N_MASK (0x1f << 8) 433 #define CCU_PLL6_FACTOR_N_SHIFT 8 434 #define CCU_PLL6_FACTOR_K(x) (((x) >> 4) & 0x3) 435 #define CCU_PLL6_FACTOR_K_MASK (0x3 << 4) 436 #define CCU_PLL6_FACTOR_K_SHIFT 4 437 #define CCU_PLL6_FACTOR_M(x) (((x) >> 0) & 0x3) 438 #define CCU_PLL6_FACTOR_M_MASK (0x3 << 0) 439 #define CCU_PLL6_FACTOR_M_SHIFT 0 440 441 uint32_t 442 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells) 443 { 444 struct sxiccmu_clock *sc = cookie; 445 uint32_t reg, k, m, n, freq; 446 uint32_t idx = cells[0]; 447 448 /* XXX Assume bypass is disabled. */ 449 reg = SXIREAD4(sc, 0); 450 k = CCU_PLL6_FACTOR_K(reg) + 1; 451 m = CCU_PLL6_FACTOR_M(reg) + 1; 452 n = CCU_PLL6_FACTOR_N(reg); 453 454 freq = clock_get_frequency_idx(sc->sc_node, 0); 455 switch (idx) { 456 case 0: 457 return (freq * n * k) / m / 6; /* pll6_sata */ 458 case 1: 459 return (freq * n * k) / 2; /* pll6_other */ 460 case 2: 461 return (freq * n * k); /* pll6 */ 462 case 3: 463 return (freq * n * k) / 4; /* pll6_div_4 */ 464 } 465 466 return 0; 467 } 468 469 void 470 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on) 471 { 472 struct sxiccmu_clock *sc = cookie; 473 uint32_t idx = cells[0]; 474 uint32_t reg; 475 476 /* 477 * Since this clock has several outputs, we never turn it off. 478 */ 479 480 reg = SXIREAD4(sc, 0); 481 switch (idx) { 482 case 0: /* pll6_sata */ 483 if (on) 484 reg |= CCU_PLL6_SATA_CLK_EN; 485 else 486 reg &= ~CCU_PLL6_SATA_CLK_EN; 487 /* FALLTHROUGH */ 488 case 1: /* pll6_other */ 489 case 2: /* pll6 */ 490 case 3: /* pll6_div_4 */ 491 if (on) 492 reg |= CCU_PLL6_ENABLE; 493 } 494 SXIWRITE4(sc, 0, reg); 495 } 496 497 #define CCU_APB1_CLK_RAT_N(x) (((x) >> 16) & 0x3) 498 #define CCU_APB1_CLK_RAT_M(x) (((x) >> 0) & 0x1f) 499 #define CCU_APB1_CLK_SRC_SEL(x) (((x) >> 24) & 0x3) 500 501 uint32_t 502 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells) 503 { 504 struct sxiccmu_clock *sc = cookie; 505 uint32_t reg, m, n, freq; 506 int idx; 507 508 reg = SXIREAD4(sc, 0); 509 m = CCU_APB1_CLK_RAT_M(reg); 510 n = CCU_APB1_CLK_RAT_N(reg); 511 idx = CCU_APB1_CLK_SRC_SEL(reg); 512 513 freq = clock_get_frequency_idx(sc->sc_node, idx); 514 return freq / (1 << n) / (m + 1); 515 } 516 517 #define CCU_GMAC_CLK_PIT (1 << 2) 518 #define CCU_GMAC_CLK_TCS (3 << 0) 519 #define CCU_GMAC_CLK_TCS_MII 0 520 #define CCU_GMAC_CLK_TCS_EXT_125 1 521 #define CCU_GMAC_CLK_TCS_INT_RGMII 2 522 523 int 524 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 525 { 526 struct sxiccmu_clock *sc = cookie; 527 528 switch (freq) { 529 case 25000000: /* MMI, 25 MHz */ 530 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 531 CCU_GMAC_CLK_TCS_MII); 532 break; 533 case 125000000: /* RGMII, 125 MHz */ 534 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 535 CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII); 536 break; 537 default: 538 return -1; 539 } 540 541 return 0; 542 } 543 544 #define CCU_SDx_SCLK_GATING (1U << 31) 545 #define CCU_SDx_CLK_SRC_SEL_OSC24M (0 << 24) 546 #define CCU_SDx_CLK_SRC_SEL_PLL6 (1 << 24) 547 #define CCU_SDx_CLK_SRC_SEL_PLL5 (2 << 24) 548 #define CCU_SDx_CLK_SRC_SEL_MASK (3 << 24) 549 #define CCU_SDx_CLK_DIV_RATIO_N_MASK (3 << 16) 550 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT 16 551 #define CCU_SDx_CLK_DIV_RATIO_M_MASK (7 << 0) 552 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT 0 553 554 int 555 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq, 556 uint32_t parent_freq) 557 { 558 uint32_t reg, m, n; 559 uint32_t clk_src; 560 561 switch (freq) { 562 case 400000: 563 n = 2, m = 15; 564 clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M; 565 break; 566 case 25000000: 567 case 26000000: 568 case 50000000: 569 case 52000000: 570 n = 0, m = 0; 571 clk_src = CCU_SDx_CLK_SRC_SEL_PLL6; 572 while ((parent_freq / (1 << n) / 16) > freq) 573 n++; 574 while ((parent_freq / (1 << n) / (m + 1)) > freq) 575 m++; 576 break; 577 default: 578 return -1; 579 } 580 581 reg = SXIREAD4(sc, 0); 582 reg &= ~CCU_SDx_CLK_SRC_SEL_MASK; 583 reg |= clk_src; 584 reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK; 585 reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT; 586 reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK; 587 reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT; 588 SXIWRITE4(sc, 0, reg); 589 590 return 0; 591 } 592 593 int 594 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 595 { 596 struct sxiccmu_clock *sc = cookie; 597 uint32_t parent_freq; 598 599 if (cells[0] != 0) 600 return -1; 601 602 parent_freq = clock_get_frequency_idx(sc->sc_node, 1); 603 return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq); 604 } 605 606 void 607 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on) 608 { 609 struct sxiccmu_clock *sc = cookie; 610 611 if (cells[0] != 0) 612 return; 613 614 if (on) 615 SXISET4(sc, 0, CCU_SDx_SCLK_GATING); 616 else 617 SXICLR4(sc, 0, CCU_SDx_SCLK_GATING); 618 } 619 620 void 621 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on) 622 { 623 struct sxiccmu_clock *sc = cookie; 624 int reg = cells[0] / 32; 625 int bit = cells[0] % 32; 626 627 if (on) { 628 clock_enable(sc->sc_node, NULL); 629 SXISET4(sc, reg * 4, (1U << bit)); 630 } else { 631 SXICLR4(sc, reg * 4, (1U << bit)); 632 clock_disable(sc->sc_node, NULL); 633 } 634 } 635 636 void 637 sxiccmu_reset(void *cookie, uint32_t *cells, int assert) 638 { 639 struct sxiccmu_clock *sc = cookie; 640 int reg = cells[0] / 32; 641 int bit = cells[0] % 32; 642 643 if (assert) 644 SXICLR4(sc, reg * 4, (1U << bit)); 645 else 646 SXISET4(sc, reg * 4, (1U << bit)); 647 } 648 649 /* 650 * Newer device trees, such as those for the Allwinner H3/A64 have 651 * most of the clock nodes replaced with a single clock control unit 652 * node. 653 */ 654 655 uint32_t 656 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells) 657 { 658 struct sxiccmu_softc *sc = cookie; 659 uint32_t idx = cells[0]; 660 uint32_t parent; 661 662 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 663 parent = sc->sc_gates[idx].parent; 664 return sxiccmu_ccu_get_frequency(sc, &parent); 665 } 666 667 return sc->sc_get_frequency(sc, idx); 668 } 669 670 /* Allwinner H3/A64 */ 671 #define CCU_AHB1_APB1_CFG_REG 0x0054 672 #define CCU_AHB1_CLK_SRC_SEL (3 << 12) 673 #define CCU_AHB1_CLK_SRC_SEL_LOSC (0 << 12) 674 #define CCU_AHB1_CLK_SRC_SEL_OSC24M (1 << 12) 675 #define CCU_AHB1_CLK_SRC_SEL_AXI (2 << 12) 676 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0 (3 << 12) 677 #define CCU_AHB1_PRE_DIV(x) ((((x) >> 6) & 3) + 1) 678 #define CCU_AHB1_CLK_DIV_RATIO(x) (1 << (((x) >> 4) & 3)) 679 #define CCU_AHB2_CFG_REG 0x005c 680 #define CCU_AHB2_CLK_CFG (3 << 0) 681 682 uint32_t 683 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 684 { 685 uint32_t parent; 686 uint32_t reg, div; 687 688 switch (idx) { 689 case A64_CLK_LOSC: 690 return clock_get_frequency(sc->sc_node, "losc"); 691 case A64_CLK_HOSC: 692 return clock_get_frequency(sc->sc_node, "hosc"); 693 case A64_CLK_PLL_PERIPH0: 694 /* Not hardcoded, but recommended. */ 695 return 600000000; 696 case A64_CLK_PLL_PERIPH0_2X: 697 return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2; 698 case A64_CLK_APB2: 699 /* XXX Controlled by a MUX. */ 700 return 24000000; 701 case A64_CLK_AHB1: 702 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 703 div = CCU_AHB1_CLK_DIV_RATIO(reg); 704 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 705 case CCU_AHB1_CLK_SRC_SEL_LOSC: 706 parent = A64_CLK_LOSC; 707 break; 708 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 709 parent = A64_CLK_HOSC; 710 break; 711 case CCU_AHB1_CLK_SRC_SEL_AXI: 712 parent = A64_CLK_AXI; 713 break; 714 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 715 parent = A64_CLK_PLL_PERIPH0; 716 div *= CCU_AHB1_PRE_DIV(reg); 717 break; 718 default: 719 return 0; 720 } 721 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 722 case A64_CLK_AHB2: 723 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 724 switch (reg & CCU_AHB2_CLK_CFG) { 725 case 0: 726 parent = A64_CLK_AHB1; 727 div = 1; 728 break; 729 case 1: 730 parent = A64_CLK_PLL_PERIPH0; 731 div = 2; 732 break; 733 default: 734 return 0; 735 } 736 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 737 } 738 739 printf("%s: 0x%08x\n", __func__, idx); 740 return 0; 741 } 742 743 uint32_t 744 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 745 { 746 uint32_t parent; 747 uint32_t reg, div; 748 749 switch (idx) { 750 case H3_CLK_LOSC: 751 return clock_get_frequency(sc->sc_node, "losc"); 752 case H3_CLK_HOSC: 753 return clock_get_frequency(sc->sc_node, "hosc"); 754 case H3_CLK_PLL_PERIPH0: 755 /* Not hardcoded, but recommended. */ 756 return 600000000; 757 case H3_CLK_APB2: 758 /* XXX Controlled by a MUX. */ 759 return 24000000; 760 case H3_CLK_AHB1: 761 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 762 div = CCU_AHB1_CLK_DIV_RATIO(reg); 763 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 764 case CCU_AHB1_CLK_SRC_SEL_LOSC: 765 parent = H3_CLK_LOSC; 766 break; 767 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 768 parent = H3_CLK_HOSC; 769 break; 770 case CCU_AHB1_CLK_SRC_SEL_AXI: 771 parent = H3_CLK_AXI; 772 break; 773 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 774 parent = H3_CLK_PLL_PERIPH0; 775 div *= CCU_AHB1_PRE_DIV(reg); 776 break; 777 default: 778 return 0; 779 } 780 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 781 case H3_CLK_AHB2: 782 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 783 switch (reg & CCU_AHB2_CLK_CFG) { 784 case 0: 785 parent = H3_CLK_AHB1; 786 div = 1; 787 break; 788 case 1: 789 parent = H3_CLK_PLL_PERIPH0; 790 div = 2; 791 break; 792 default: 793 return 0; 794 } 795 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 796 } 797 798 printf("%s: 0x%08x\n", __func__, idx); 799 return 0; 800 } 801 802 int 803 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 804 { 805 struct sxiccmu_softc *sc = cookie; 806 uint32_t idx = cells[0]; 807 808 return sc->sc_set_frequency(sc, idx, freq); 809 } 810 811 int 812 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 813 { 814 struct sxiccmu_clock clock; 815 uint32_t parent, parent_freq; 816 817 switch (idx) { 818 case A64_CLK_MMC0: 819 case A64_CLK_MMC1: 820 case A64_CLK_MMC2: 821 clock.sc_iot = sc->sc_iot; 822 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 823 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 824 parent = A64_CLK_PLL_PERIPH0_2X; 825 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 826 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 827 } 828 829 printf("%s: 0x%08x\n", __func__, idx); 830 return -1; 831 } 832 833 int 834 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 835 { 836 struct sxiccmu_clock clock; 837 uint32_t parent, parent_freq; 838 839 switch (idx) { 840 case H3_CLK_MMC0: 841 case H3_CLK_MMC1: 842 case H3_CLK_MMC2: 843 clock.sc_iot = sc->sc_iot; 844 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 845 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 846 parent = H3_CLK_PLL_PERIPH0; 847 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 848 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 849 } 850 851 printf("%s: 0x%08x\n", __func__, idx); 852 return -1; 853 } 854 855 void 856 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on) 857 { 858 struct sxiccmu_softc *sc = cookie; 859 uint32_t idx = cells[0]; 860 int reg, bit; 861 862 if (idx >= sc->sc_ngates || sc->sc_gates[idx].reg == 0) { 863 printf("%s: 0x%08x\n", __func__, cells[0]); 864 return; 865 } 866 867 reg = sc->sc_gates[idx].reg; 868 bit = sc->sc_gates[idx].bit; 869 870 if (on) 871 SXISET4(sc, reg, (1U << bit)); 872 else 873 SXICLR4(sc, reg, (1U << bit)); 874 } 875 876 void 877 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert) 878 { 879 struct sxiccmu_softc *sc = cookie; 880 uint32_t idx = cells[0]; 881 int reg, bit; 882 883 if (idx >= sc->sc_nresets || sc->sc_resets[idx].reg == 0) { 884 printf("%s: 0x%08x\n", __func__, cells[0]); 885 return; 886 } 887 888 reg = sc->sc_resets[idx].reg; 889 bit = sc->sc_resets[idx].bit; 890 891 if (assert) 892 SXICLR4(sc, reg, (1U << bit)); 893 else 894 SXISET4(sc, reg, (1U << bit)); 895 } 896