1 /* $OpenBSD: sxiccmu.c,v 1.17 2017/12/31 10:54:39 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2013 Artturi Alm 5 * Copyright (c) 2016,2017 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, 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_a10_get_frequency(struct sxiccmu_softc *, uint32_t); 90 int sxiccmu_a10_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 91 uint32_t sxiccmu_a23_get_frequency(struct sxiccmu_softc *, uint32_t); 92 int sxiccmu_a23_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 93 uint32_t sxiccmu_a64_get_frequency(struct sxiccmu_softc *, uint32_t); 94 int sxiccmu_a64_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 95 uint32_t sxiccmu_a80_get_frequency(struct sxiccmu_softc *, uint32_t); 96 int sxiccmu_a80_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 97 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t); 98 int sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 99 uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t); 100 uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t); 101 int sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 102 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t); 103 int sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 104 105 int 106 sxiccmu_match(struct device *parent, void *match, void *aux) 107 { 108 struct fdt_attach_args *faa = aux; 109 int node = faa->fa_node; 110 111 if (node == OF_finddevice("/clocks")) { 112 node = OF_parent(node); 113 114 return (OF_is_compatible(node, "allwinner,sun4i-a10") || 115 OF_is_compatible(node, "allwinner,sun5i-a10s") || 116 OF_is_compatible(node, "allwinner,sun5i-r8") || 117 OF_is_compatible(node, "allwinner,sun7i-a20") || 118 OF_is_compatible(node, "allwinner,sun8i-a23") || 119 OF_is_compatible(node, "allwinner,sun8i-a33") || 120 OF_is_compatible(node, "allwinner,sun8i-h3") || 121 OF_is_compatible(node, "allwinner,sun9i-a80") || 122 OF_is_compatible(node, "allwinner,sun50i-a64") || 123 OF_is_compatible(node, "allwinner,sun50i-h5")); 124 } 125 126 return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") || 127 OF_is_compatible(node, "allwinner,sun7i-a20-ccu") || 128 OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || 129 OF_is_compatible(node, "allwinner,sun8i-a23-prcm") || 130 OF_is_compatible(node, "allwinner,sun8i-a33-ccu") || 131 OF_is_compatible(node, "allwinner,sun8i-h3-ccu") || 132 OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") || 133 OF_is_compatible(node, "allwinner,sun8i-r40-ccu") || 134 OF_is_compatible(node, "allwinner,sun9i-a80-ccu") || 135 OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") || 136 OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") || 137 OF_is_compatible(node, "allwinner,sun50i-a64-ccu") || 138 OF_is_compatible(node, "allwinner,sun50i-h5-ccu")); 139 } 140 141 void 142 sxiccmu_attach(struct device *parent, struct device *self, void *aux) 143 { 144 struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self; 145 struct fdt_attach_args *faa = aux; 146 int node = faa->fa_node; 147 148 sc->sc_node = faa->fa_node; 149 sc->sc_iot = faa->fa_iot; 150 if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot, 151 faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh)) 152 panic("%s: bus_space_map failed!", __func__); 153 154 printf("\n"); 155 156 if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") || 157 OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) { 158 KASSERT(faa->fa_nreg > 0); 159 sc->sc_gates = sun4i_a10_gates; 160 sc->sc_ngates = nitems(sun4i_a10_gates); 161 sc->sc_resets = sun4i_a10_resets; 162 sc->sc_nresets = nitems(sun4i_a10_resets); 163 sc->sc_get_frequency = sxiccmu_a10_get_frequency; 164 sc->sc_set_frequency = sxiccmu_a10_set_frequency; 165 } else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || 166 OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) { 167 KASSERT(faa->fa_nreg > 0); 168 sc->sc_gates = sun8i_a23_gates; 169 sc->sc_ngates = nitems(sun8i_a23_gates); 170 sc->sc_resets = sun8i_a23_resets; 171 sc->sc_nresets = nitems(sun8i_a23_resets); 172 sc->sc_get_frequency = sxiccmu_a23_get_frequency; 173 sc->sc_set_frequency = sxiccmu_a23_set_frequency; 174 } else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") || 175 OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) { 176 KASSERT(faa->fa_nreg > 0); 177 sc->sc_gates = sun8i_h3_gates; 178 sc->sc_ngates = nitems(sun8i_h3_gates); 179 sc->sc_resets = sun8i_h3_resets; 180 sc->sc_nresets = nitems(sun8i_h3_resets); 181 sc->sc_get_frequency = sxiccmu_h3_get_frequency; 182 sc->sc_set_frequency = sxiccmu_h3_set_frequency; 183 } else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu")) { 184 KASSERT(faa->fa_nreg > 0); 185 sc->sc_gates = sun8i_h3_r_gates; 186 sc->sc_ngates = nitems(sun8i_h3_r_gates); 187 sc->sc_resets = sun8i_h3_r_resets; 188 sc->sc_nresets = nitems(sun8i_h3_r_resets); 189 sc->sc_get_frequency = sxiccmu_h3_r_get_frequency; 190 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 191 } else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) { 192 KASSERT(faa->fa_nreg > 0); 193 sc->sc_gates = sun8i_r40_gates; 194 sc->sc_ngates = nitems(sun8i_r40_gates); 195 sc->sc_resets = sun8i_r40_resets; 196 sc->sc_nresets = nitems(sun8i_r40_resets); 197 sc->sc_get_frequency = sxiccmu_r40_get_frequency; 198 sc->sc_set_frequency = sxiccmu_r40_set_frequency; 199 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) { 200 KASSERT(faa->fa_nreg > 0); 201 sc->sc_gates = sun9i_a80_gates; 202 sc->sc_ngates = nitems(sun9i_a80_gates); 203 sc->sc_resets = sun9i_a80_resets; 204 sc->sc_nresets = nitems(sun9i_a80_resets); 205 sc->sc_get_frequency = sxiccmu_a80_get_frequency; 206 sc->sc_set_frequency = sxiccmu_a80_set_frequency; 207 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) { 208 KASSERT(faa->fa_nreg > 0); 209 sc->sc_gates = sun9i_a80_usb_gates; 210 sc->sc_ngates = nitems(sun9i_a80_usb_gates); 211 sc->sc_resets = sun9i_a80_usb_resets; 212 sc->sc_nresets = nitems(sun9i_a80_usb_resets); 213 sc->sc_get_frequency = sxiccmu_nop_get_frequency; 214 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 215 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) { 216 KASSERT(faa->fa_nreg > 0); 217 sc->sc_gates = sun9i_a80_mmc_gates; 218 sc->sc_ngates = nitems(sun9i_a80_mmc_gates); 219 sc->sc_resets = sun9i_a80_mmc_resets; 220 sc->sc_nresets = nitems(sun9i_a80_mmc_resets); 221 sc->sc_get_frequency = sxiccmu_nop_get_frequency; 222 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 223 } else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) { 224 KASSERT(faa->fa_nreg > 0); 225 sc->sc_gates = sun50i_a64_gates; 226 sc->sc_ngates = nitems(sun50i_a64_gates); 227 sc->sc_resets = sun50i_a64_resets; 228 sc->sc_nresets = nitems(sun50i_a64_resets); 229 sc->sc_get_frequency = sxiccmu_a64_get_frequency; 230 sc->sc_set_frequency = sxiccmu_a64_set_frequency; 231 } else { 232 for (node = OF_child(node); node; node = OF_peer(node)) 233 sxiccmu_attach_clock(sc, node, faa->fa_nreg); 234 } 235 236 if (sc->sc_gates) { 237 sc->sc_cd.cd_node = sc->sc_node; 238 sc->sc_cd.cd_cookie = sc; 239 sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency; 240 sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency; 241 sc->sc_cd.cd_enable = sxiccmu_ccu_enable; 242 clock_register(&sc->sc_cd); 243 } 244 245 if (sc->sc_resets) { 246 sc->sc_rd.rd_node = sc->sc_node; 247 sc->sc_rd.rd_cookie = sc; 248 sc->sc_rd.rd_reset = sxiccmu_ccu_reset; 249 reset_register(&sc->sc_rd); 250 } 251 } 252 253 /* 254 * Classic device trees for the Allwinner SoCs have basically a clock 255 * node per register of the clock control unit. Attaching a separate 256 * driver to each of them would be crazy, so we handle them here. 257 */ 258 259 struct sxiccmu_clock { 260 int sc_node; 261 bus_space_tag_t sc_iot; 262 bus_space_handle_t sc_ioh; 263 264 struct clock_device sc_cd; 265 struct reset_device sc_rd; 266 }; 267 268 struct sxiccmu_device { 269 const char *compat; 270 uint32_t (*get_frequency)(void *, uint32_t *); 271 int (*set_frequency)(void *, uint32_t *, uint32_t); 272 void (*enable)(void *, uint32_t *, int); 273 void (*reset)(void *, uint32_t *, int); 274 bus_size_t offset; 275 }; 276 277 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *); 278 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *); 279 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *); 280 void sxiccmu_pll6_enable(void *, uint32_t *, int); 281 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *); 282 uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *); 283 uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *); 284 int sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t); 285 int sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t); 286 void sxiccmu_mmc_enable(void *, uint32_t *, int); 287 void sxiccmu_gate_enable(void *, uint32_t *, int); 288 void sxiccmu_reset(void *, uint32_t *, int); 289 290 struct sxiccmu_device sxiccmu_devices[] = { 291 { 292 .compat = "allwinner,sun4i-a10-osc-clk", 293 .get_frequency = sxiccmu_osc_get_frequency, 294 }, 295 { 296 .compat = "allwinner,sun4i-a10-pll6-clk", 297 .get_frequency = sxiccmu_pll6_get_frequency, 298 .enable = sxiccmu_pll6_enable 299 }, 300 { 301 .compat = "allwinner,sun4i-a10-apb1-clk", 302 .get_frequency = sxiccmu_apb1_get_frequency, 303 }, 304 { 305 .compat = "allwinner,sun4i-a10-ahb-gates-clk", 306 .get_frequency = sxiccmu_gen_get_frequency, 307 .enable = sxiccmu_gate_enable 308 }, 309 { 310 .compat = "allwinner,sun4i-a10-apb0-gates-clk", 311 .get_frequency = sxiccmu_gen_get_frequency, 312 .enable = sxiccmu_gate_enable 313 }, 314 { 315 .compat = "allwinner,sun4i-a10-apb1-gates-clk", 316 .get_frequency = sxiccmu_gen_get_frequency, 317 .enable = sxiccmu_gate_enable 318 }, 319 { 320 .compat = "allwinner,sun4i-a10-mmc-clk", 321 .set_frequency = sxiccmu_mmc_set_frequency, 322 .enable = sxiccmu_mmc_enable 323 }, 324 { 325 .compat = "allwinner,sun4i-a10-usb-clk", 326 .get_frequency = sxiccmu_gen_get_frequency, 327 .enable = sxiccmu_gate_enable, 328 .reset = sxiccmu_reset 329 }, 330 { 331 .compat = "allwinner,sun5i-a10s-ahb-gates-clk", 332 .get_frequency = sxiccmu_gen_get_frequency, 333 .enable = sxiccmu_gate_enable 334 }, 335 { 336 .compat = "allwinner,sun5i-a10s-apb0-gates-clk", 337 .get_frequency = sxiccmu_gen_get_frequency, 338 .enable = sxiccmu_gate_enable 339 }, 340 { 341 .compat = "allwinner,sun5i-a10s-apb1-gates-clk", 342 .get_frequency = sxiccmu_gen_get_frequency, 343 .enable = sxiccmu_gate_enable 344 }, 345 { 346 .compat = "allwinner,sun5i-a13-ahb-gates-clk", 347 .get_frequency = sxiccmu_gen_get_frequency, 348 .enable = sxiccmu_gate_enable 349 }, 350 { 351 .compat = "allwinner,sun5i-a13-apb0-gates-clk", 352 .get_frequency = sxiccmu_gen_get_frequency, 353 .enable = sxiccmu_gate_enable 354 }, 355 { 356 .compat = "allwinner,sun5i-a13-apb1-gates-clk", 357 .get_frequency = sxiccmu_gen_get_frequency, 358 .enable = sxiccmu_gate_enable 359 }, 360 { 361 .compat = "allwinner,sun5i-a13-usb-clk", 362 .get_frequency = sxiccmu_gen_get_frequency, 363 .enable = sxiccmu_gate_enable, 364 .reset = sxiccmu_reset 365 }, 366 { 367 .compat = "allwinner,sun6i-a31-ahb1-reset", 368 .reset = sxiccmu_reset 369 }, 370 { 371 .compat = "allwinner,sun6i-a31-clock-reset", 372 .reset = sxiccmu_reset, 373 .offset = 0x00b0 374 }, 375 { 376 .compat = "allwinner,sun7i-a20-ahb-gates-clk", 377 .get_frequency = sxiccmu_gen_get_frequency, 378 .enable = sxiccmu_gate_enable 379 }, 380 { 381 .compat = "allwinner,sun7i-a20-apb0-gates-clk", 382 .get_frequency = sxiccmu_gen_get_frequency, 383 .enable = sxiccmu_gate_enable 384 }, 385 { 386 .compat = "allwinner,sun7i-a20-apb1-gates-clk", 387 .get_frequency = sxiccmu_gen_get_frequency, 388 .enable = sxiccmu_gate_enable 389 }, 390 { 391 .compat = "allwinner,sun7i-a20-gmac-clk", 392 .set_frequency = sxiccmu_gmac_set_frequency 393 }, 394 { 395 .compat = "allwinner,sun8i-a23-apb0-clk", 396 .get_frequency = sxiccmu_apbs_get_frequency, 397 .offset = 0x000c 398 }, 399 { 400 .compat = "allwinner,sun8i-a23-ahb1-gates-clk", 401 .get_frequency = sxiccmu_gen_get_frequency, 402 .enable = sxiccmu_gate_enable 403 }, 404 { 405 .compat = "allwinner,sun8i-a23-apb0-gates-clk", 406 .get_frequency = sxiccmu_gen_get_frequency, 407 .enable = sxiccmu_gate_enable, 408 .offset = 0x0028 409 }, 410 { 411 .compat = "allwinner,sun8i-a23-apb1-gates-clk", 412 .get_frequency = sxiccmu_gen_get_frequency, 413 .enable = sxiccmu_gate_enable 414 }, 415 { 416 .compat = "allwinner,sun8i-a23-apb2-gates-clk", 417 .get_frequency = sxiccmu_gen_get_frequency, 418 .enable = sxiccmu_gate_enable 419 }, 420 { 421 .compat = "allwinner,sun8i-a23-usb-clk", 422 .get_frequency = sxiccmu_gen_get_frequency, 423 .enable = sxiccmu_gate_enable, 424 .reset = sxiccmu_reset 425 }, 426 { 427 .compat = "allwinner,sun8i-h3-apb0-gates-clk", 428 .get_frequency = sxiccmu_gen_get_frequency, 429 .enable = sxiccmu_gate_enable 430 }, 431 { 432 .compat = "allwinner,sun9i-a80-apb1-clk", 433 .get_frequency = sxiccmu_apb1_get_frequency, 434 }, 435 { 436 .compat = "allwinner,sun9i-a80-ahb0-gates-clk", 437 .get_frequency = sxiccmu_gen_get_frequency, 438 .enable = sxiccmu_gate_enable 439 }, 440 { 441 .compat = "allwinner,sun9i-a80-ahb1-gates-clk", 442 .get_frequency = sxiccmu_gen_get_frequency, 443 .enable = sxiccmu_gate_enable 444 }, 445 { 446 .compat = "allwinner,sun9i-a80-ahb2-gates-clk", 447 .get_frequency = sxiccmu_gen_get_frequency, 448 .enable = sxiccmu_gate_enable 449 }, 450 { 451 .compat = "allwinner,sun9i-a80-apb0-gates-clk", 452 .get_frequency = sxiccmu_gen_get_frequency, 453 .enable = sxiccmu_gate_enable 454 }, 455 { 456 .compat = "allwinner,sun9i-a80-apb1-gates-clk", 457 .get_frequency = sxiccmu_gen_get_frequency, 458 .enable = sxiccmu_gate_enable 459 }, 460 { 461 .compat = "allwinner,sun9i-a80-apbs-gates-clk", 462 .get_frequency = sxiccmu_gen_get_frequency, 463 .enable = sxiccmu_gate_enable 464 }, 465 { 466 .compat = "allwinner,sun9i-a80-cpus-clk", 467 .get_frequency = sxiccmu_cpus_get_frequency 468 }, 469 { 470 .compat = "allwinner,sun9i-a80-mmc-clk", 471 .set_frequency = sxiccmu_mmc_set_frequency, 472 .enable = sxiccmu_mmc_enable 473 }, 474 { 475 .compat = "allwinner,sun9i-a80-usb-mod-clk", 476 .get_frequency = sxiccmu_gen_get_frequency, 477 .enable = sxiccmu_gate_enable, 478 .reset = sxiccmu_reset 479 }, 480 { 481 .compat = "allwinner,sun9i-a80-usb-phy-clk", 482 .get_frequency = sxiccmu_gen_get_frequency, 483 .enable = sxiccmu_gate_enable, 484 .reset = sxiccmu_reset 485 }, 486 }; 487 488 void 489 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg) 490 { 491 struct sxiccmu_clock *clock; 492 uint32_t reg[2]; 493 int i, error = ENODEV; 494 495 for (i = 0; i < nitems(sxiccmu_devices); i++) 496 if (OF_is_compatible(node, sxiccmu_devices[i].compat)) 497 break; 498 if (i == nitems(sxiccmu_devices)) 499 return; 500 501 clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK); 502 clock->sc_node = node; 503 504 clock->sc_iot = sc->sc_iot; 505 if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) { 506 error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0, 507 &clock->sc_ioh); 508 } else if (nreg > 0) { 509 error = bus_space_subregion(clock->sc_iot, sc->sc_ioh, 510 sxiccmu_devices[i].offset, 4, &clock->sc_ioh); 511 } 512 if (error) { 513 printf("%s: can't map registers", sc->sc_dev.dv_xname); 514 free(clock, M_DEVBUF, sizeof(*clock)); 515 return; 516 } 517 518 clock->sc_cd.cd_node = node; 519 clock->sc_cd.cd_cookie = clock; 520 clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency; 521 clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency; 522 clock->sc_cd.cd_enable = sxiccmu_devices[i].enable; 523 clock_register(&clock->sc_cd); 524 525 if (sxiccmu_devices[i].reset) { 526 clock->sc_rd.rd_node = node; 527 clock->sc_rd.rd_cookie = clock; 528 clock->sc_rd.rd_reset = sxiccmu_devices[i].reset; 529 reset_register(&clock->sc_rd); 530 } 531 } 532 533 /* 534 * A "generic" function that simply gets the clock frequency from the 535 * parent clock. Useful for clock gating devices that don't scale 536 * their clocks. 537 */ 538 uint32_t 539 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells) 540 { 541 struct sxiccmu_clock *sc = cookie; 542 543 return clock_get_frequency(sc->sc_node, NULL); 544 } 545 546 uint32_t 547 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells) 548 { 549 struct sxiccmu_clock *sc = cookie; 550 551 return OF_getpropint(sc->sc_node, "clock-frequency", 24000000); 552 } 553 554 #define CCU_PLL6_ENABLE (1U << 31) 555 #define CCU_PLL6_BYPASS_EN (1U << 30) 556 #define CCU_PLL6_SATA_CLK_EN (1U << 14) 557 #define CCU_PLL6_FACTOR_N(x) (((x) >> 8) & 0x1f) 558 #define CCU_PLL6_FACTOR_N_MASK (0x1f << 8) 559 #define CCU_PLL6_FACTOR_N_SHIFT 8 560 #define CCU_PLL6_FACTOR_K(x) (((x) >> 4) & 0x3) 561 #define CCU_PLL6_FACTOR_K_MASK (0x3 << 4) 562 #define CCU_PLL6_FACTOR_K_SHIFT 4 563 #define CCU_PLL6_FACTOR_M(x) (((x) >> 0) & 0x3) 564 #define CCU_PLL6_FACTOR_M_MASK (0x3 << 0) 565 #define CCU_PLL6_FACTOR_M_SHIFT 0 566 567 uint32_t 568 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells) 569 { 570 struct sxiccmu_clock *sc = cookie; 571 uint32_t reg, k, m, n, freq; 572 uint32_t idx = cells[0]; 573 574 /* XXX Assume bypass is disabled. */ 575 reg = SXIREAD4(sc, 0); 576 k = CCU_PLL6_FACTOR_K(reg) + 1; 577 m = CCU_PLL6_FACTOR_M(reg) + 1; 578 n = CCU_PLL6_FACTOR_N(reg); 579 580 freq = clock_get_frequency_idx(sc->sc_node, 0); 581 switch (idx) { 582 case 0: 583 return (freq * n * k) / m / 6; /* pll6_sata */ 584 case 1: 585 return (freq * n * k) / 2; /* pll6_other */ 586 case 2: 587 return (freq * n * k); /* pll6 */ 588 case 3: 589 return (freq * n * k) / 4; /* pll6_div_4 */ 590 } 591 592 return 0; 593 } 594 595 void 596 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on) 597 { 598 struct sxiccmu_clock *sc = cookie; 599 uint32_t idx = cells[0]; 600 uint32_t reg; 601 602 /* 603 * Since this clock has several outputs, we never turn it off. 604 */ 605 606 reg = SXIREAD4(sc, 0); 607 switch (idx) { 608 case 0: /* pll6_sata */ 609 if (on) 610 reg |= CCU_PLL6_SATA_CLK_EN; 611 else 612 reg &= ~CCU_PLL6_SATA_CLK_EN; 613 /* FALLTHROUGH */ 614 case 1: /* pll6_other */ 615 case 2: /* pll6 */ 616 case 3: /* pll6_div_4 */ 617 if (on) 618 reg |= CCU_PLL6_ENABLE; 619 } 620 SXIWRITE4(sc, 0, reg); 621 } 622 623 #define CCU_APB1_CLK_RAT_N(x) (((x) >> 16) & 0x3) 624 #define CCU_APB1_CLK_RAT_M(x) (((x) >> 0) & 0x1f) 625 #define CCU_APB1_CLK_SRC_SEL(x) (((x) >> 24) & 0x3) 626 627 uint32_t 628 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells) 629 { 630 struct sxiccmu_clock *sc = cookie; 631 uint32_t reg, m, n, freq; 632 int idx; 633 634 reg = SXIREAD4(sc, 0); 635 m = CCU_APB1_CLK_RAT_M(reg); 636 n = CCU_APB1_CLK_RAT_N(reg); 637 idx = CCU_APB1_CLK_SRC_SEL(reg); 638 639 freq = clock_get_frequency_idx(sc->sc_node, idx); 640 return freq / (1 << n) / (m + 1); 641 } 642 643 #define CCU_CPUS_CLK_SRC_SEL(x) (((x) >> 16) & 0x3) 644 #define CCU_CPUS_POST_DIV(x) (((x) >> 8) & 0x1f) 645 #define CCU_CPUS_CLK_RATIO(x) (((x) >> 0) & 0x3) 646 647 uint32_t 648 sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells) 649 { 650 struct sxiccmu_clock *sc = cookie; 651 uint32_t reg, post_div, clk_ratio, freq; 652 int idx; 653 654 reg = SXIREAD4(sc, 0); 655 idx = CCU_CPUS_CLK_SRC_SEL(reg); 656 post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0); 657 clk_ratio = CCU_CPUS_CLK_RATIO(reg); 658 659 freq = clock_get_frequency_idx(sc->sc_node, idx); 660 return freq / (clk_ratio + 1) / (post_div + 1); 661 } 662 663 #define CCU_APBS_CLK_RATIO(x) (((x) >> 0) & 0x3) 664 665 uint32_t 666 sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells) 667 { 668 struct sxiccmu_clock *sc = cookie; 669 uint32_t reg, freq; 670 671 reg = SXIREAD4(sc, 0); 672 freq = clock_get_frequency(sc->sc_node, NULL); 673 return freq / (CCU_APBS_CLK_RATIO(reg) + 1); 674 } 675 676 #define CCU_GMAC_CLK_PIT (1 << 2) 677 #define CCU_GMAC_CLK_TCS (3 << 0) 678 #define CCU_GMAC_CLK_TCS_MII 0 679 #define CCU_GMAC_CLK_TCS_EXT_125 1 680 #define CCU_GMAC_CLK_TCS_INT_RGMII 2 681 682 int 683 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 684 { 685 struct sxiccmu_clock *sc = cookie; 686 687 switch (freq) { 688 case 25000000: /* MMI, 25 MHz */ 689 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 690 CCU_GMAC_CLK_TCS_MII); 691 break; 692 case 125000000: /* RGMII, 125 MHz */ 693 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 694 CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII); 695 break; 696 default: 697 return -1; 698 } 699 700 return 0; 701 } 702 703 #define CCU_SDx_SCLK_GATING (1U << 31) 704 #define CCU_SDx_CLK_SRC_SEL_OSC24M (0 << 24) 705 #define CCU_SDx_CLK_SRC_SEL_PLL6 (1 << 24) 706 #define CCU_SDx_CLK_SRC_SEL_PLL5 (2 << 24) 707 #define CCU_SDx_CLK_SRC_SEL_MASK (3 << 24) 708 #define CCU_SDx_CLK_DIV_RATIO_N_MASK (3 << 16) 709 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT 16 710 #define CCU_SDx_CLK_DIV_RATIO_M_MASK (7 << 0) 711 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT 0 712 713 int 714 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq, 715 uint32_t parent_freq) 716 { 717 uint32_t reg, m, n; 718 uint32_t clk_src; 719 720 switch (freq) { 721 case 400000: 722 n = 2, m = 15; 723 clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M; 724 break; 725 case 25000000: 726 case 26000000: 727 case 50000000: 728 case 52000000: 729 n = 0, m = 0; 730 clk_src = CCU_SDx_CLK_SRC_SEL_PLL6; 731 while ((parent_freq / (1 << n) / 16) > freq) 732 n++; 733 while ((parent_freq / (1 << n) / (m + 1)) > freq) 734 m++; 735 break; 736 default: 737 return -1; 738 } 739 740 reg = SXIREAD4(sc, 0); 741 reg &= ~CCU_SDx_CLK_SRC_SEL_MASK; 742 reg |= clk_src; 743 reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK; 744 reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT; 745 reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK; 746 reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT; 747 SXIWRITE4(sc, 0, reg); 748 749 return 0; 750 } 751 752 int 753 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 754 { 755 struct sxiccmu_clock *sc = cookie; 756 uint32_t parent_freq; 757 758 if (cells[0] != 0) 759 return -1; 760 761 parent_freq = clock_get_frequency_idx(sc->sc_node, 1); 762 return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq); 763 } 764 765 void 766 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on) 767 { 768 struct sxiccmu_clock *sc = cookie; 769 770 if (cells[0] != 0) 771 return; 772 773 if (on) 774 SXISET4(sc, 0, CCU_SDx_SCLK_GATING); 775 else 776 SXICLR4(sc, 0, CCU_SDx_SCLK_GATING); 777 } 778 779 void 780 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on) 781 { 782 struct sxiccmu_clock *sc = cookie; 783 int reg = cells[0] / 32; 784 int bit = cells[0] % 32; 785 786 if (on) { 787 clock_enable(sc->sc_node, NULL); 788 SXISET4(sc, reg * 4, (1U << bit)); 789 } else { 790 SXICLR4(sc, reg * 4, (1U << bit)); 791 clock_disable(sc->sc_node, NULL); 792 } 793 } 794 795 void 796 sxiccmu_reset(void *cookie, uint32_t *cells, int assert) 797 { 798 struct sxiccmu_clock *sc = cookie; 799 int reg = cells[0] / 32; 800 int bit = cells[0] % 32; 801 802 if (assert) 803 SXICLR4(sc, reg * 4, (1U << bit)); 804 else 805 SXISET4(sc, reg * 4, (1U << bit)); 806 } 807 808 /* 809 * Newer device trees, such as those for the Allwinner H3/A64 have 810 * most of the clock nodes replaced with a single clock control unit 811 * node. 812 */ 813 814 uint32_t 815 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells) 816 { 817 struct sxiccmu_softc *sc = cookie; 818 uint32_t idx = cells[0]; 819 uint32_t parent; 820 821 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 822 parent = sc->sc_gates[idx].parent; 823 return sxiccmu_ccu_get_frequency(sc, &parent); 824 } 825 826 return sc->sc_get_frequency(sc, idx); 827 } 828 829 /* Allwinner A10/A20 */ 830 #define A10_PLL1_CFG_REG 0x0000 831 #define A10_PLL1_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) 832 #define A10_PLL1_FACTOR_N(x) (((x) >> 8) & 0x1f) 833 #define A10_PLL1_FACTOR_K(x) (((x) >> 4) & 0x3) 834 #define A10_PLL1_FACTOR_M(x) (((x) >> 0) & 0x3) 835 #define A10_CPU_AHB_APB0_CFG_REG 0x0054 836 #define A10_CPU_CLK_SRC_SEL (0x3 << 16) 837 #define A10_CPU_CLK_SRC_SEL_LOSC (0x0 << 16) 838 #define A10_CPU_CLK_SRC_SEL_OSC24M (0x1 << 16) 839 #define A10_CPU_CLK_SRC_SEL_PLL1 (0x2 << 16) 840 #define A10_CPU_CLK_SRC_SEL_200MHZ (0x3 << 16) 841 842 uint32_t 843 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 844 { 845 uint32_t parent; 846 uint32_t reg, k, m, n, p; 847 848 switch (idx) { 849 case A10_CLK_LOSC: 850 return clock_get_frequency(sc->sc_node, "losc"); 851 case A10_CLK_HOSC: 852 return clock_get_frequency(sc->sc_node, "hosc"); 853 case A10_CLK_PLL_CORE: 854 reg = SXIREAD4(sc, A10_PLL1_CFG_REG); 855 k = A10_PLL1_FACTOR_K(reg) + 1; 856 m = A10_PLL1_FACTOR_M(reg) + 1; 857 n = A10_PLL1_FACTOR_N(reg); 858 p = 1 << A10_PLL1_OUT_EXT_DIVP(reg); 859 return (24000000 * n * k) / (m * p); 860 case A10_CLK_PLL_PERIPH_BASE: 861 /* Not hardcoded, but recommended. */ 862 return 600000000; 863 case A10_CLK_PLL_PERIPH: 864 return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2; 865 case A10_CLK_CPU: 866 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 867 switch (reg & A10_CPU_CLK_SRC_SEL) { 868 case A10_CPU_CLK_SRC_SEL_LOSC: 869 parent = A10_CLK_LOSC; 870 break; 871 case A10_CPU_CLK_SRC_SEL_OSC24M: 872 parent = A10_CLK_HOSC; 873 break; 874 case A10_CPU_CLK_SRC_SEL_PLL1: 875 parent = A10_CLK_PLL_CORE; 876 break; 877 case A10_CPU_CLK_SRC_SEL_200MHZ: 878 return 200000000; 879 } 880 return sxiccmu_ccu_get_frequency(sc, &parent); 881 case A10_CLK_APB1: 882 /* XXX Controlled by a MUX. */ 883 return 24000000; 884 } 885 886 printf("%s: 0x%08x\n", __func__, idx); 887 return 0; 888 } 889 890 /* Allwinner H3/A64 */ 891 #define CCU_AHB1_APB1_CFG_REG 0x0054 892 #define CCU_AHB1_CLK_SRC_SEL (3 << 12) 893 #define CCU_AHB1_CLK_SRC_SEL_LOSC (0 << 12) 894 #define CCU_AHB1_CLK_SRC_SEL_OSC24M (1 << 12) 895 #define CCU_AHB1_CLK_SRC_SEL_AXI (2 << 12) 896 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0 (3 << 12) 897 #define CCU_AHB1_PRE_DIV(x) ((((x) >> 6) & 3) + 1) 898 #define CCU_AHB1_CLK_DIV_RATIO(x) (1 << (((x) >> 4) & 3)) 899 #define CCU_AHB2_CFG_REG 0x005c 900 #define CCU_AHB2_CLK_CFG (3 << 0) 901 902 uint32_t 903 sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 904 { 905 uint32_t parent; 906 uint32_t reg, div; 907 908 switch (idx) { 909 case A23_CLK_LOSC: 910 return clock_get_frequency(sc->sc_node, "losc"); 911 case A23_CLK_HOSC: 912 return clock_get_frequency(sc->sc_node, "hosc"); 913 case A23_CLK_PLL_PERIPH: 914 /* Not hardcoded, but recommended. */ 915 return 600000000; 916 case A23_CLK_APB2: 917 /* XXX Controlled by a MUX. */ 918 return 24000000; 919 case A23_CLK_AHB1: 920 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 921 div = CCU_AHB1_CLK_DIV_RATIO(reg); 922 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 923 case CCU_AHB1_CLK_SRC_SEL_LOSC: 924 parent = A23_CLK_LOSC; 925 break; 926 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 927 parent = A23_CLK_HOSC; 928 break; 929 case CCU_AHB1_CLK_SRC_SEL_AXI: 930 parent = A23_CLK_AXI; 931 break; 932 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 933 parent = A23_CLK_PLL_PERIPH; 934 div *= CCU_AHB1_PRE_DIV(reg); 935 break; 936 default: 937 return 0; 938 } 939 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 940 } 941 942 printf("%s: 0x%08x\n", __func__, idx); 943 return 0; 944 } 945 946 uint32_t 947 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 948 { 949 uint32_t parent; 950 uint32_t reg, div; 951 952 switch (idx) { 953 case A64_CLK_LOSC: 954 return clock_get_frequency(sc->sc_node, "losc"); 955 case A64_CLK_HOSC: 956 return clock_get_frequency(sc->sc_node, "hosc"); 957 case A64_CLK_PLL_PERIPH0: 958 /* Not hardcoded, but recommended. */ 959 return 600000000; 960 case A64_CLK_PLL_PERIPH0_2X: 961 return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2; 962 case A64_CLK_APB2: 963 /* XXX Controlled by a MUX. */ 964 return 24000000; 965 case A64_CLK_AHB1: 966 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 967 div = CCU_AHB1_CLK_DIV_RATIO(reg); 968 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 969 case CCU_AHB1_CLK_SRC_SEL_LOSC: 970 parent = A64_CLK_LOSC; 971 break; 972 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 973 parent = A64_CLK_HOSC; 974 break; 975 case CCU_AHB1_CLK_SRC_SEL_AXI: 976 parent = A64_CLK_AXI; 977 break; 978 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 979 parent = A64_CLK_PLL_PERIPH0; 980 div *= CCU_AHB1_PRE_DIV(reg); 981 break; 982 default: 983 return 0; 984 } 985 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 986 case A64_CLK_AHB2: 987 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 988 switch (reg & CCU_AHB2_CLK_CFG) { 989 case 0: 990 parent = A64_CLK_AHB1; 991 div = 1; 992 break; 993 case 1: 994 parent = A64_CLK_PLL_PERIPH0; 995 div = 2; 996 break; 997 default: 998 return 0; 999 } 1000 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1001 } 1002 1003 printf("%s: 0x%08x\n", __func__, idx); 1004 return 0; 1005 } 1006 1007 uint32_t 1008 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1009 { 1010 switch (idx) { 1011 case A80_CLK_PLL_PERIPH0: 1012 /* Not hardcoded, but recommended. */ 1013 return 960000000; 1014 case A80_CLK_APB1: 1015 /* XXX Controlled by a MUX. */ 1016 return 24000000; 1017 } 1018 1019 printf("%s: 0x%08x\n", __func__, idx); 1020 return 0; 1021 } 1022 1023 /* Allwinner H3/H5 */ 1024 #define H3_PLL_CPUX_CTRL_REG 0x0000 1025 #define H3_PLL_CPUX_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) 1026 #define H3_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f) 1027 #define H3_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3) 1028 #define H3_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3) 1029 #define H3_CPUX_AXI_CFG_REG 0x0050 1030 #define H3_CPUX_CLK_SRC_SEL (0x3 << 16) 1031 #define H3_CPUX_CLK_SRC_SEL_LOSC (0x0 << 16) 1032 #define H3_CPUX_CLK_SRC_SEL_OSC24M (0x1 << 16) 1033 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX (0x2 << 16) 1034 1035 uint32_t 1036 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1037 { 1038 uint32_t parent; 1039 uint32_t reg, div; 1040 uint32_t k, m, n, p; 1041 1042 switch (idx) { 1043 case H3_CLK_LOSC: 1044 return clock_get_frequency(sc->sc_node, "losc"); 1045 case H3_CLK_HOSC: 1046 return clock_get_frequency(sc->sc_node, "hosc"); 1047 case H3_CLK_PLL_CPUX: 1048 reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG); 1049 k = H3_PLL_CPUX_FACTOR_K(reg) + 1; 1050 m = H3_PLL_CPUX_FACTOR_M(reg) + 1; 1051 n = H3_PLL_CPUX_FACTOR_N(reg) + 1; 1052 p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg); 1053 return (24000000 * n * k) / (m * p); 1054 case H3_CLK_PLL_PERIPH0: 1055 /* Not hardcoded, but recommended. */ 1056 return 600000000; 1057 case H3_CLK_CPUX: 1058 reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG); 1059 switch (reg & H3_CPUX_CLK_SRC_SEL) { 1060 case H3_CPUX_CLK_SRC_SEL_LOSC: 1061 parent = H3_CLK_LOSC; 1062 break; 1063 case H3_CPUX_CLK_SRC_SEL_OSC24M: 1064 parent = H3_CLK_HOSC; 1065 break; 1066 case H3_CPUX_CLK_SRC_SEL_PLL_CPUX: 1067 parent = H3_CLK_PLL_CPUX; 1068 break; 1069 default: 1070 return 0; 1071 } 1072 return sxiccmu_ccu_get_frequency(sc, &parent); 1073 case H3_CLK_APB2: 1074 /* XXX Controlled by a MUX. */ 1075 return 24000000; 1076 case H3_CLK_AHB1: 1077 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1078 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1079 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1080 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1081 parent = H3_CLK_LOSC; 1082 break; 1083 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1084 parent = H3_CLK_HOSC; 1085 break; 1086 case CCU_AHB1_CLK_SRC_SEL_AXI: 1087 parent = H3_CLK_AXI; 1088 break; 1089 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1090 parent = H3_CLK_PLL_PERIPH0; 1091 div *= CCU_AHB1_PRE_DIV(reg); 1092 break; 1093 default: 1094 return 0; 1095 } 1096 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1097 case H3_CLK_AHB2: 1098 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 1099 switch (reg & CCU_AHB2_CLK_CFG) { 1100 case 0: 1101 parent = H3_CLK_AHB1; 1102 div = 1; 1103 break; 1104 case 1: 1105 parent = H3_CLK_PLL_PERIPH0; 1106 div = 2; 1107 break; 1108 default: 1109 return 0; 1110 } 1111 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1112 } 1113 1114 printf("%s: 0x%08x\n", __func__, idx); 1115 return 0; 1116 } 1117 1118 #define H3_AHB0_CLK_REG 0x0000 1119 #define H3_AHB0_CLK_SRC_SEL (0x3 << 16) 1120 #define H3_AHB0_CLK_SRC_SEL_OSC32K (0x0 << 16) 1121 #define H3_AHB0_CLK_SRC_SEL_OSC24M (0x1 << 16) 1122 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0 (0x2 << 16) 1123 #define H3_AHB0_CLK_SRC_SEL_IOSC (0x3 << 16) 1124 #define H3_AHB0_CLK_PRE_DIV(x) ((((x) >> 8) & 0x1f) + 1) 1125 #define H3_AHB0_CLK_RATIO(x) (1 << (((x) >> 4) & 3)) 1126 #define H3_APB0_CFG_REG 0x000c 1127 #define H3_APB0_CLK_RATIO(x) (1 << ((x) & 1)) 1128 1129 uint32_t 1130 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1131 { 1132 uint32_t parent; 1133 uint32_t reg, div; 1134 uint32_t freq; 1135 1136 switch (idx) { 1137 case H3_R_CLK_AHB0: 1138 reg = SXIREAD4(sc, H3_AHB0_CLK_REG); 1139 switch (reg & H3_AHB0_CLK_SRC_SEL) { 1140 case H3_AHB0_CLK_SRC_SEL_OSC32K: 1141 freq = clock_get_frequency(sc->sc_node, "losc"); 1142 break; 1143 case H3_AHB0_CLK_SRC_SEL_OSC24M: 1144 freq = clock_get_frequency(sc->sc_node, "hosc"); 1145 break; 1146 case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0: 1147 freq = clock_get_frequency(sc->sc_node, "pll-periph"); 1148 break; 1149 case H3_AHB0_CLK_SRC_SEL_IOSC: 1150 freq = clock_get_frequency(sc->sc_node, "iosc"); 1151 break; 1152 } 1153 div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg); 1154 return freq / div; 1155 case H3_R_CLK_APB0: 1156 reg = SXIREAD4(sc, H3_APB0_CFG_REG); 1157 div = H3_APB0_CLK_RATIO(reg); 1158 parent = H3_R_CLK_AHB0; 1159 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1160 } 1161 1162 printf("%s: 0x%08x\n", __func__, idx); 1163 return 0; 1164 } 1165 1166 uint32_t 1167 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1168 { 1169 switch (idx) { 1170 case R40_CLK_PLL_PERIPH0: 1171 /* Not hardcoded, but recommended. */ 1172 return 600000000; 1173 case R40_CLK_PLL_PERIPH0_2X: 1174 return sxiccmu_r40_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2; 1175 case R40_CLK_APB2: 1176 /* XXX Controlled by a MUX. */ 1177 return 24000000; 1178 } 1179 1180 printf("%s: 0x%08x\n", __func__, idx); 1181 return 0; 1182 } 1183 1184 uint32_t 1185 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1186 { 1187 printf("%s: 0x%08x\n", __func__, idx); 1188 return 0; 1189 } 1190 1191 int 1192 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 1193 { 1194 struct sxiccmu_softc *sc = cookie; 1195 uint32_t idx = cells[0]; 1196 1197 return sc->sc_set_frequency(sc, idx, freq); 1198 } 1199 1200 int 1201 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1202 { 1203 struct sxiccmu_clock clock; 1204 uint32_t parent, parent_freq; 1205 1206 switch (idx) { 1207 case A10_CLK_MMC0: 1208 case A10_CLK_MMC1: 1209 case A10_CLK_MMC2: 1210 case A10_CLK_MMC3: 1211 clock.sc_iot = sc->sc_iot; 1212 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1213 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1214 parent = A10_CLK_PLL_PERIPH; 1215 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1216 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1217 } 1218 1219 printf("%s: 0x%08x\n", __func__, idx); 1220 return -1; 1221 } 1222 1223 int 1224 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1225 { 1226 struct sxiccmu_clock clock; 1227 uint32_t parent, parent_freq; 1228 1229 switch (idx) { 1230 case A23_CLK_MMC0: 1231 case A23_CLK_MMC1: 1232 case A23_CLK_MMC2: 1233 clock.sc_iot = sc->sc_iot; 1234 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1235 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1236 parent = A23_CLK_PLL_PERIPH; 1237 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1238 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1239 } 1240 1241 printf("%s: 0x%08x\n", __func__, idx); 1242 return -1; 1243 } 1244 1245 int 1246 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1247 { 1248 struct sxiccmu_clock clock; 1249 uint32_t parent, parent_freq; 1250 1251 switch (idx) { 1252 case A64_CLK_MMC0: 1253 case A64_CLK_MMC1: 1254 case A64_CLK_MMC2: 1255 clock.sc_iot = sc->sc_iot; 1256 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1257 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1258 parent = A64_CLK_PLL_PERIPH0_2X; 1259 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1260 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1261 } 1262 1263 printf("%s: 0x%08x\n", __func__, idx); 1264 return -1; 1265 } 1266 1267 int 1268 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1269 { 1270 struct sxiccmu_clock clock; 1271 uint32_t parent, parent_freq; 1272 1273 switch (idx) { 1274 case A80_CLK_MMC0: 1275 case A80_CLK_MMC1: 1276 case A80_CLK_MMC2: 1277 clock.sc_iot = sc->sc_iot; 1278 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1279 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1280 parent = A80_CLK_PLL_PERIPH0; 1281 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1282 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1283 } 1284 1285 printf("%s: 0x%08x\n", __func__, idx); 1286 return -1; 1287 } 1288 1289 int 1290 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1291 { 1292 struct sxiccmu_clock clock; 1293 uint32_t parent, parent_freq; 1294 1295 switch (idx) { 1296 case H3_CLK_MMC0: 1297 case H3_CLK_MMC1: 1298 case H3_CLK_MMC2: 1299 clock.sc_iot = sc->sc_iot; 1300 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1301 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1302 parent = H3_CLK_PLL_PERIPH0; 1303 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1304 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1305 } 1306 1307 printf("%s: 0x%08x\n", __func__, idx); 1308 return -1; 1309 } 1310 1311 int 1312 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1313 { 1314 struct sxiccmu_clock clock; 1315 uint32_t parent, parent_freq; 1316 1317 switch (idx) { 1318 case R40_CLK_MMC0: 1319 case R40_CLK_MMC1: 1320 case R40_CLK_MMC2: 1321 case R40_CLK_MMC3: 1322 clock.sc_iot = sc->sc_iot; 1323 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1324 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1325 parent = R40_CLK_PLL_PERIPH0_2X; 1326 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1327 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1328 } 1329 1330 printf("%s: 0x%08x\n", __func__, idx); 1331 return -1; 1332 } 1333 1334 int 1335 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1336 { 1337 printf("%s: 0x%08x\n", __func__, idx); 1338 return -1; 1339 } 1340 1341 void 1342 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on) 1343 { 1344 struct sxiccmu_softc *sc = cookie; 1345 uint32_t idx = cells[0]; 1346 int reg, bit; 1347 1348 clock_enable_all(sc->sc_node); 1349 1350 if (idx >= sc->sc_ngates || 1351 (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) { 1352 printf("%s: 0x%08x\n", __func__, cells[0]); 1353 return; 1354 } 1355 1356 reg = sc->sc_gates[idx].reg; 1357 bit = sc->sc_gates[idx].bit; 1358 1359 if (on) 1360 SXISET4(sc, reg, (1U << bit)); 1361 else 1362 SXICLR4(sc, reg, (1U << bit)); 1363 } 1364 1365 void 1366 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert) 1367 { 1368 struct sxiccmu_softc *sc = cookie; 1369 uint32_t idx = cells[0]; 1370 int reg, bit; 1371 1372 reset_deassert_all(sc->sc_node); 1373 1374 if (idx >= sc->sc_nresets || 1375 (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) { 1376 printf("%s: 0x%08x\n", __func__, cells[0]); 1377 return; 1378 } 1379 1380 reg = sc->sc_resets[idx].reg; 1381 bit = sc->sc_resets[idx].bit; 1382 1383 if (assert) 1384 SXICLR4(sc, reg, (1U << bit)); 1385 else 1386 SXISET4(sc, reg, (1U << bit)); 1387 } 1388