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