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