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