1 /* $OpenBSD: sxiccmu.c,v 1.35 2024/02/07 22:00:38 uaa 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 const struct sxiccmu_ccu_bit *sc_gates; 62 int sc_ngates; 63 struct clock_device sc_cd; 64 65 const 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 const 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_d1_get_frequency(struct sxiccmu_softc *, uint32_t); 102 int sxiccmu_d1_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 103 uint32_t sxiccmu_h3_get_frequency(struct sxiccmu_softc *, uint32_t); 104 int sxiccmu_h3_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 105 uint32_t sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *, uint32_t); 106 uint32_t sxiccmu_h6_get_frequency(struct sxiccmu_softc *, uint32_t); 107 int sxiccmu_h6_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 108 uint32_t sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *, uint32_t); 109 uint32_t sxiccmu_h616_get_frequency(struct sxiccmu_softc *, uint32_t); 110 int sxiccmu_h616_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 111 uint32_t sxiccmu_h616_r_get_frequency(struct sxiccmu_softc *, uint32_t); 112 uint32_t sxiccmu_r40_get_frequency(struct sxiccmu_softc *, uint32_t); 113 int sxiccmu_r40_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 114 uint32_t sxiccmu_v3s_get_frequency(struct sxiccmu_softc *, uint32_t); 115 int sxiccmu_v3s_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 116 uint32_t sxiccmu_nop_get_frequency(struct sxiccmu_softc *, uint32_t); 117 int sxiccmu_nop_set_frequency(struct sxiccmu_softc *, uint32_t, uint32_t); 118 119 int 120 sxiccmu_match(struct device *parent, void *match, void *aux) 121 { 122 struct fdt_attach_args *faa = aux; 123 int node = faa->fa_node; 124 125 if (node == OF_finddevice("/clocks")) { 126 node = OF_parent(node); 127 128 return (OF_is_compatible(node, "allwinner,sun4i-a10") || 129 OF_is_compatible(node, "allwinner,sun5i-a10s") || 130 OF_is_compatible(node, "allwinner,sun5i-r8") || 131 OF_is_compatible(node, "allwinner,sun7i-a20") || 132 OF_is_compatible(node, "allwinner,sun8i-a23") || 133 OF_is_compatible(node, "allwinner,sun8i-a33") || 134 OF_is_compatible(node, "allwinner,sun8i-h3") || 135 OF_is_compatible(node, "allwinner,sun8i-v3s") || 136 OF_is_compatible(node, "allwinner,sun9i-a80") || 137 OF_is_compatible(node, "allwinner,sun50i-a64") || 138 OF_is_compatible(node, "allwinner,sun50i-h5")); 139 } 140 141 return (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") || 142 OF_is_compatible(node, "allwinner,sun7i-a20-ccu") || 143 OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || 144 OF_is_compatible(node, "allwinner,sun8i-a23-prcm") || 145 OF_is_compatible(node, "allwinner,sun8i-a33-ccu") || 146 OF_is_compatible(node, "allwinner,sun8i-h3-ccu") || 147 OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") || 148 OF_is_compatible(node, "allwinner,sun8i-r40-ccu") || 149 OF_is_compatible(node, "allwinner,sun8i-v3s-ccu") || 150 OF_is_compatible(node, "allwinner,sun9i-a80-ccu") || 151 OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks") || 152 OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk") || 153 OF_is_compatible(node, "allwinner,sun20i-d1-ccu") || 154 OF_is_compatible(node, "allwinner,sun50i-a64-ccu") || 155 OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu") || 156 OF_is_compatible(node, "allwinner,sun50i-h5-ccu") || 157 OF_is_compatible(node, "allwinner,sun50i-h6-ccu") || 158 OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu") || 159 OF_is_compatible(node, "allwinner,sun50i-h616-ccu") || 160 OF_is_compatible(node, "allwinner,sun50i-h616-r-ccu")); 161 } 162 163 void 164 sxiccmu_attach(struct device *parent, struct device *self, void *aux) 165 { 166 struct sxiccmu_softc *sc = (struct sxiccmu_softc *)self; 167 struct fdt_attach_args *faa = aux; 168 int node = faa->fa_node; 169 170 sc->sc_node = faa->fa_node; 171 sc->sc_iot = faa->fa_iot; 172 if (faa->fa_nreg > 0 && bus_space_map(sc->sc_iot, 173 faa->fa_reg[0].addr, faa->fa_reg[0].size, 0, &sc->sc_ioh)) 174 panic("%s: bus_space_map failed!", __func__); 175 176 /* On the R40, the GMAC needs to poke at one of our registers. */ 177 if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) { 178 bus_space_handle_t ioh; 179 180 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 181 R40_GMAC_CLK_REG, 4, &ioh); 182 regmap_register(faa->fa_node, sc->sc_iot, ioh, 4); 183 } 184 185 printf("\n"); 186 187 if (OF_is_compatible(node, "allwinner,sun4i-a10-ccu") || 188 OF_is_compatible(node, "allwinner,sun7i-a20-ccu")) { 189 KASSERT(faa->fa_nreg > 0); 190 sc->sc_gates = sun4i_a10_gates; 191 sc->sc_ngates = nitems(sun4i_a10_gates); 192 sc->sc_resets = sun4i_a10_resets; 193 sc->sc_nresets = nitems(sun4i_a10_resets); 194 sc->sc_get_frequency = sxiccmu_a10_get_frequency; 195 sc->sc_set_frequency = sxiccmu_a10_set_frequency; 196 } else if (OF_is_compatible(node, "allwinner,sun8i-a23-ccu") || 197 OF_is_compatible(node, "allwinner,sun8i-a33-ccu")) { 198 KASSERT(faa->fa_nreg > 0); 199 sc->sc_gates = sun8i_a23_gates; 200 sc->sc_ngates = nitems(sun8i_a23_gates); 201 sc->sc_resets = sun8i_a23_resets; 202 sc->sc_nresets = nitems(sun8i_a23_resets); 203 sc->sc_get_frequency = sxiccmu_a23_get_frequency; 204 sc->sc_set_frequency = sxiccmu_a23_set_frequency; 205 } else if (OF_is_compatible(node, "allwinner,sun8i-h3-ccu") || 206 OF_is_compatible(node, "allwinner,sun50i-h5-ccu")) { 207 KASSERT(faa->fa_nreg > 0); 208 sc->sc_gates = sun8i_h3_gates; 209 sc->sc_ngates = nitems(sun8i_h3_gates); 210 sc->sc_resets = sun8i_h3_resets; 211 sc->sc_nresets = nitems(sun8i_h3_resets); 212 sc->sc_get_frequency = sxiccmu_h3_get_frequency; 213 sc->sc_set_frequency = sxiccmu_h3_set_frequency; 214 } else if (OF_is_compatible(node, "allwinner,sun8i-h3-r-ccu") || 215 OF_is_compatible(node, "allwinner,sun50i-a64-r-ccu")) { 216 KASSERT(faa->fa_nreg > 0); 217 sc->sc_gates = sun8i_h3_r_gates; 218 sc->sc_ngates = nitems(sun8i_h3_r_gates); 219 sc->sc_resets = sun8i_h3_r_resets; 220 sc->sc_nresets = nitems(sun8i_h3_r_resets); 221 sc->sc_get_frequency = sxiccmu_h3_r_get_frequency; 222 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 223 } else if (OF_is_compatible(node, "allwinner,sun8i-r40-ccu")) { 224 KASSERT(faa->fa_nreg > 0); 225 sc->sc_gates = sun8i_r40_gates; 226 sc->sc_ngates = nitems(sun8i_r40_gates); 227 sc->sc_resets = sun8i_r40_resets; 228 sc->sc_nresets = nitems(sun8i_r40_resets); 229 sc->sc_get_frequency = sxiccmu_r40_get_frequency; 230 sc->sc_set_frequency = sxiccmu_r40_set_frequency; 231 } else if (OF_is_compatible(node, "allwinner,sun8i-v3s-ccu")) { 232 KASSERT(faa->fa_nreg > 0); 233 sc->sc_gates = sun8i_v3s_gates; 234 sc->sc_ngates = nitems(sun8i_v3s_gates); 235 sc->sc_resets = sun8i_v3s_resets; 236 sc->sc_nresets = nitems(sun8i_v3s_resets); 237 sc->sc_get_frequency = sxiccmu_v3s_get_frequency; 238 sc->sc_set_frequency = sxiccmu_v3s_set_frequency; 239 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-ccu")) { 240 KASSERT(faa->fa_nreg > 0); 241 sc->sc_gates = sun9i_a80_gates; 242 sc->sc_ngates = nitems(sun9i_a80_gates); 243 sc->sc_resets = sun9i_a80_resets; 244 sc->sc_nresets = nitems(sun9i_a80_resets); 245 sc->sc_get_frequency = sxiccmu_a80_get_frequency; 246 sc->sc_set_frequency = sxiccmu_a80_set_frequency; 247 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-usb-clks")) { 248 KASSERT(faa->fa_nreg > 0); 249 sc->sc_gates = sun9i_a80_usb_gates; 250 sc->sc_ngates = nitems(sun9i_a80_usb_gates); 251 sc->sc_resets = sun9i_a80_usb_resets; 252 sc->sc_nresets = nitems(sun9i_a80_usb_resets); 253 sc->sc_get_frequency = sxiccmu_nop_get_frequency; 254 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 255 } else if (OF_is_compatible(node, "allwinner,sun9i-a80-mmc-config-clk")) { 256 KASSERT(faa->fa_nreg > 0); 257 sc->sc_gates = sun9i_a80_mmc_gates; 258 sc->sc_ngates = nitems(sun9i_a80_mmc_gates); 259 sc->sc_resets = sun9i_a80_mmc_resets; 260 sc->sc_nresets = nitems(sun9i_a80_mmc_resets); 261 sc->sc_get_frequency = sxiccmu_nop_get_frequency; 262 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 263 } else if (OF_is_compatible(node, "allwinner,sun20i-d1-ccu")) { 264 KASSERT(faa->fa_nreg > 0); 265 sc->sc_gates = sun20i_d1_gates; 266 sc->sc_ngates = nitems(sun20i_d1_gates); 267 sc->sc_resets = sun20i_d1_resets; 268 sc->sc_nresets = nitems(sun20i_d1_resets); 269 sc->sc_get_frequency = sxiccmu_d1_get_frequency; 270 sc->sc_set_frequency = sxiccmu_d1_set_frequency; 271 } else if (OF_is_compatible(node, "allwinner,sun50i-a64-ccu")) { 272 KASSERT(faa->fa_nreg > 0); 273 sc->sc_gates = sun50i_a64_gates; 274 sc->sc_ngates = nitems(sun50i_a64_gates); 275 sc->sc_resets = sun50i_a64_resets; 276 sc->sc_nresets = nitems(sun50i_a64_resets); 277 sc->sc_get_frequency = sxiccmu_a64_get_frequency; 278 sc->sc_set_frequency = sxiccmu_a64_set_frequency; 279 } else if (OF_is_compatible(node, "allwinner,sun50i-h6-ccu")) { 280 KASSERT(faa->fa_nreg > 0); 281 sc->sc_gates = sun50i_h6_gates; 282 sc->sc_ngates = nitems(sun50i_h6_gates); 283 sc->sc_resets = sun50i_h6_resets; 284 sc->sc_nresets = nitems(sun50i_h6_resets); 285 sc->sc_get_frequency = sxiccmu_h6_get_frequency; 286 sc->sc_set_frequency = sxiccmu_h6_set_frequency; 287 } else if (OF_is_compatible(node, "allwinner,sun50i-h6-r-ccu")) { 288 KASSERT(faa->fa_nreg > 0); 289 sc->sc_gates = sun50i_h6_r_gates; 290 sc->sc_ngates = nitems(sun50i_h6_r_gates); 291 sc->sc_resets = sun50i_h6_r_resets; 292 sc->sc_nresets = nitems(sun50i_h6_r_resets); 293 sc->sc_get_frequency = sxiccmu_h6_r_get_frequency; 294 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 295 } else if (OF_is_compatible(node, "allwinner,sun50i-h616-ccu")) { 296 KASSERT(faa->fa_nreg > 0); 297 sc->sc_gates = sun50i_h616_gates; 298 sc->sc_ngates = nitems(sun50i_h616_gates); 299 sc->sc_resets = sun50i_h616_resets; 300 sc->sc_nresets = nitems(sun50i_h616_resets); 301 sc->sc_get_frequency = sxiccmu_h616_get_frequency; 302 sc->sc_set_frequency = sxiccmu_h616_set_frequency; 303 } else if (OF_is_compatible(node, "allwinner,sun50i-h616-r-ccu")) { 304 KASSERT(faa->fa_nreg > 0); 305 sc->sc_gates = sun50i_h616_r_gates; 306 sc->sc_ngates = nitems(sun50i_h616_r_gates); 307 sc->sc_resets = sun50i_h616_r_resets; 308 sc->sc_nresets = nitems(sun50i_h616_r_resets); 309 sc->sc_get_frequency = sxiccmu_h616_r_get_frequency; 310 sc->sc_set_frequency = sxiccmu_nop_set_frequency; 311 } else { 312 for (node = OF_child(node); node; node = OF_peer(node)) 313 sxiccmu_attach_clock(sc, node, faa->fa_nreg); 314 } 315 316 if (sc->sc_gates) { 317 sc->sc_cd.cd_node = sc->sc_node; 318 sc->sc_cd.cd_cookie = sc; 319 sc->sc_cd.cd_get_frequency = sxiccmu_ccu_get_frequency; 320 sc->sc_cd.cd_set_frequency = sxiccmu_ccu_set_frequency; 321 sc->sc_cd.cd_enable = sxiccmu_ccu_enable; 322 clock_register(&sc->sc_cd); 323 } 324 325 if (sc->sc_resets) { 326 sc->sc_rd.rd_node = sc->sc_node; 327 sc->sc_rd.rd_cookie = sc; 328 sc->sc_rd.rd_reset = sxiccmu_ccu_reset; 329 reset_register(&sc->sc_rd); 330 } 331 } 332 333 /* 334 * Classic device trees for the Allwinner SoCs have basically a clock 335 * node per register of the clock control unit. Attaching a separate 336 * driver to each of them would be crazy, so we handle them here. 337 */ 338 339 struct sxiccmu_clock { 340 int sc_node; 341 bus_space_tag_t sc_iot; 342 bus_space_handle_t sc_ioh; 343 344 struct clock_device sc_cd; 345 struct reset_device sc_rd; 346 }; 347 348 struct sxiccmu_device { 349 const char *compat; 350 uint32_t (*get_frequency)(void *, uint32_t *); 351 int (*set_frequency)(void *, uint32_t *, uint32_t); 352 void (*enable)(void *, uint32_t *, int); 353 void (*reset)(void *, uint32_t *, int); 354 bus_size_t offset; 355 }; 356 357 uint32_t sxiccmu_gen_get_frequency(void *, uint32_t *); 358 uint32_t sxiccmu_osc_get_frequency(void *, uint32_t *); 359 uint32_t sxiccmu_pll6_get_frequency(void *, uint32_t *); 360 void sxiccmu_pll6_enable(void *, uint32_t *, int); 361 uint32_t sxiccmu_apb1_get_frequency(void *, uint32_t *); 362 uint32_t sxiccmu_cpus_get_frequency(void *, uint32_t *); 363 uint32_t sxiccmu_apbs_get_frequency(void *, uint32_t *); 364 int sxiccmu_gmac_set_frequency(void *, uint32_t *, uint32_t); 365 int sxiccmu_mmc_set_frequency(void *, uint32_t *, uint32_t); 366 void sxiccmu_mmc_enable(void *, uint32_t *, int); 367 void sxiccmu_gate_enable(void *, uint32_t *, int); 368 void sxiccmu_reset(void *, uint32_t *, int); 369 370 const struct sxiccmu_device sxiccmu_devices[] = { 371 { 372 .compat = "allwinner,sun4i-a10-osc-clk", 373 .get_frequency = sxiccmu_osc_get_frequency, 374 }, 375 { 376 .compat = "allwinner,sun4i-a10-pll6-clk", 377 .get_frequency = sxiccmu_pll6_get_frequency, 378 .enable = sxiccmu_pll6_enable 379 }, 380 { 381 .compat = "allwinner,sun4i-a10-apb1-clk", 382 .get_frequency = sxiccmu_apb1_get_frequency, 383 }, 384 { 385 .compat = "allwinner,sun4i-a10-ahb-gates-clk", 386 .get_frequency = sxiccmu_gen_get_frequency, 387 .enable = sxiccmu_gate_enable 388 }, 389 { 390 .compat = "allwinner,sun4i-a10-apb0-gates-clk", 391 .get_frequency = sxiccmu_gen_get_frequency, 392 .enable = sxiccmu_gate_enable 393 }, 394 { 395 .compat = "allwinner,sun4i-a10-apb1-gates-clk", 396 .get_frequency = sxiccmu_gen_get_frequency, 397 .enable = sxiccmu_gate_enable 398 }, 399 { 400 .compat = "allwinner,sun4i-a10-mmc-clk", 401 .set_frequency = sxiccmu_mmc_set_frequency, 402 .enable = sxiccmu_mmc_enable 403 }, 404 { 405 .compat = "allwinner,sun4i-a10-usb-clk", 406 .get_frequency = sxiccmu_gen_get_frequency, 407 .enable = sxiccmu_gate_enable, 408 .reset = sxiccmu_reset 409 }, 410 { 411 .compat = "allwinner,sun5i-a10s-ahb-gates-clk", 412 .get_frequency = sxiccmu_gen_get_frequency, 413 .enable = sxiccmu_gate_enable 414 }, 415 { 416 .compat = "allwinner,sun5i-a10s-apb0-gates-clk", 417 .get_frequency = sxiccmu_gen_get_frequency, 418 .enable = sxiccmu_gate_enable 419 }, 420 { 421 .compat = "allwinner,sun5i-a10s-apb1-gates-clk", 422 .get_frequency = sxiccmu_gen_get_frequency, 423 .enable = sxiccmu_gate_enable 424 }, 425 { 426 .compat = "allwinner,sun5i-a13-ahb-gates-clk", 427 .get_frequency = sxiccmu_gen_get_frequency, 428 .enable = sxiccmu_gate_enable 429 }, 430 { 431 .compat = "allwinner,sun5i-a13-apb0-gates-clk", 432 .get_frequency = sxiccmu_gen_get_frequency, 433 .enable = sxiccmu_gate_enable 434 }, 435 { 436 .compat = "allwinner,sun5i-a13-apb1-gates-clk", 437 .get_frequency = sxiccmu_gen_get_frequency, 438 .enable = sxiccmu_gate_enable 439 }, 440 { 441 .compat = "allwinner,sun5i-a13-usb-clk", 442 .get_frequency = sxiccmu_gen_get_frequency, 443 .enable = sxiccmu_gate_enable, 444 .reset = sxiccmu_reset 445 }, 446 { 447 .compat = "allwinner,sun6i-a31-ahb1-reset", 448 .reset = sxiccmu_reset 449 }, 450 { 451 .compat = "allwinner,sun6i-a31-clock-reset", 452 .reset = sxiccmu_reset, 453 .offset = 0x00b0 454 }, 455 { 456 .compat = "allwinner,sun7i-a20-ahb-gates-clk", 457 .get_frequency = sxiccmu_gen_get_frequency, 458 .enable = sxiccmu_gate_enable 459 }, 460 { 461 .compat = "allwinner,sun7i-a20-apb0-gates-clk", 462 .get_frequency = sxiccmu_gen_get_frequency, 463 .enable = sxiccmu_gate_enable 464 }, 465 { 466 .compat = "allwinner,sun7i-a20-apb1-gates-clk", 467 .get_frequency = sxiccmu_gen_get_frequency, 468 .enable = sxiccmu_gate_enable 469 }, 470 { 471 .compat = "allwinner,sun7i-a20-gmac-clk", 472 .set_frequency = sxiccmu_gmac_set_frequency 473 }, 474 { 475 .compat = "allwinner,sun8i-a23-apb0-clk", 476 .get_frequency = sxiccmu_apbs_get_frequency, 477 .offset = 0x000c 478 }, 479 { 480 .compat = "allwinner,sun8i-a23-ahb1-gates-clk", 481 .get_frequency = sxiccmu_gen_get_frequency, 482 .enable = sxiccmu_gate_enable 483 }, 484 { 485 .compat = "allwinner,sun8i-a23-apb0-gates-clk", 486 .get_frequency = sxiccmu_gen_get_frequency, 487 .enable = sxiccmu_gate_enable, 488 .offset = 0x0028 489 }, 490 { 491 .compat = "allwinner,sun8i-a23-apb1-gates-clk", 492 .get_frequency = sxiccmu_gen_get_frequency, 493 .enable = sxiccmu_gate_enable 494 }, 495 { 496 .compat = "allwinner,sun8i-a23-apb2-gates-clk", 497 .get_frequency = sxiccmu_gen_get_frequency, 498 .enable = sxiccmu_gate_enable 499 }, 500 { 501 .compat = "allwinner,sun8i-a23-usb-clk", 502 .get_frequency = sxiccmu_gen_get_frequency, 503 .enable = sxiccmu_gate_enable, 504 .reset = sxiccmu_reset 505 }, 506 { 507 .compat = "allwinner,sun8i-h3-apb0-gates-clk", 508 .get_frequency = sxiccmu_gen_get_frequency, 509 .enable = sxiccmu_gate_enable 510 }, 511 { 512 .compat = "allwinner,sun9i-a80-apb1-clk", 513 .get_frequency = sxiccmu_apb1_get_frequency, 514 }, 515 { 516 .compat = "allwinner,sun9i-a80-ahb0-gates-clk", 517 .get_frequency = sxiccmu_gen_get_frequency, 518 .enable = sxiccmu_gate_enable 519 }, 520 { 521 .compat = "allwinner,sun9i-a80-ahb1-gates-clk", 522 .get_frequency = sxiccmu_gen_get_frequency, 523 .enable = sxiccmu_gate_enable 524 }, 525 { 526 .compat = "allwinner,sun9i-a80-ahb2-gates-clk", 527 .get_frequency = sxiccmu_gen_get_frequency, 528 .enable = sxiccmu_gate_enable 529 }, 530 { 531 .compat = "allwinner,sun9i-a80-apb0-gates-clk", 532 .get_frequency = sxiccmu_gen_get_frequency, 533 .enable = sxiccmu_gate_enable 534 }, 535 { 536 .compat = "allwinner,sun9i-a80-apb1-gates-clk", 537 .get_frequency = sxiccmu_gen_get_frequency, 538 .enable = sxiccmu_gate_enable 539 }, 540 { 541 .compat = "allwinner,sun9i-a80-apbs-gates-clk", 542 .get_frequency = sxiccmu_gen_get_frequency, 543 .enable = sxiccmu_gate_enable 544 }, 545 { 546 .compat = "allwinner,sun9i-a80-cpus-clk", 547 .get_frequency = sxiccmu_cpus_get_frequency 548 }, 549 { 550 .compat = "allwinner,sun9i-a80-mmc-clk", 551 .set_frequency = sxiccmu_mmc_set_frequency, 552 .enable = sxiccmu_mmc_enable 553 }, 554 { 555 .compat = "allwinner,sun9i-a80-usb-mod-clk", 556 .get_frequency = sxiccmu_gen_get_frequency, 557 .enable = sxiccmu_gate_enable, 558 .reset = sxiccmu_reset 559 }, 560 { 561 .compat = "allwinner,sun9i-a80-usb-phy-clk", 562 .get_frequency = sxiccmu_gen_get_frequency, 563 .enable = sxiccmu_gate_enable, 564 .reset = sxiccmu_reset 565 }, 566 }; 567 568 void 569 sxiccmu_attach_clock(struct sxiccmu_softc *sc, int node, int nreg) 570 { 571 struct sxiccmu_clock *clock; 572 uint32_t reg[2]; 573 int i, error = ENODEV; 574 575 for (i = 0; i < nitems(sxiccmu_devices); i++) 576 if (OF_is_compatible(node, sxiccmu_devices[i].compat)) 577 break; 578 if (i == nitems(sxiccmu_devices)) 579 return; 580 581 clock = malloc(sizeof(*clock), M_DEVBUF, M_WAITOK); 582 clock->sc_node = node; 583 584 clock->sc_iot = sc->sc_iot; 585 if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) == sizeof(reg)) { 586 error = bus_space_map(clock->sc_iot, reg[0], reg[1], 0, 587 &clock->sc_ioh); 588 } else if (nreg > 0) { 589 error = bus_space_subregion(clock->sc_iot, sc->sc_ioh, 590 sxiccmu_devices[i].offset, 4, &clock->sc_ioh); 591 } 592 if (error) { 593 printf("%s: can't map registers", sc->sc_dev.dv_xname); 594 free(clock, M_DEVBUF, sizeof(*clock)); 595 return; 596 } 597 598 clock->sc_cd.cd_node = node; 599 clock->sc_cd.cd_cookie = clock; 600 clock->sc_cd.cd_get_frequency = sxiccmu_devices[i].get_frequency; 601 clock->sc_cd.cd_set_frequency = sxiccmu_devices[i].set_frequency; 602 clock->sc_cd.cd_enable = sxiccmu_devices[i].enable; 603 clock_register(&clock->sc_cd); 604 605 if (sxiccmu_devices[i].reset) { 606 clock->sc_rd.rd_node = node; 607 clock->sc_rd.rd_cookie = clock; 608 clock->sc_rd.rd_reset = sxiccmu_devices[i].reset; 609 reset_register(&clock->sc_rd); 610 } 611 } 612 613 /* 614 * A "generic" function that simply gets the clock frequency from the 615 * parent clock. Useful for clock gating devices that don't scale 616 * their clocks. 617 */ 618 uint32_t 619 sxiccmu_gen_get_frequency(void *cookie, uint32_t *cells) 620 { 621 struct sxiccmu_clock *sc = cookie; 622 623 return clock_get_frequency(sc->sc_node, NULL); 624 } 625 626 uint32_t 627 sxiccmu_osc_get_frequency(void *cookie, uint32_t *cells) 628 { 629 struct sxiccmu_clock *sc = cookie; 630 631 return OF_getpropint(sc->sc_node, "clock-frequency", 24000000); 632 } 633 634 #define CCU_PLL6_ENABLE (1U << 31) 635 #define CCU_PLL6_BYPASS_EN (1U << 30) 636 #define CCU_PLL6_SATA_CLK_EN (1U << 14) 637 #define CCU_PLL6_FACTOR_N(x) (((x) >> 8) & 0x1f) 638 #define CCU_PLL6_FACTOR_N_MASK (0x1f << 8) 639 #define CCU_PLL6_FACTOR_N_SHIFT 8 640 #define CCU_PLL6_FACTOR_K(x) (((x) >> 4) & 0x3) 641 #define CCU_PLL6_FACTOR_K_MASK (0x3 << 4) 642 #define CCU_PLL6_FACTOR_K_SHIFT 4 643 #define CCU_PLL6_FACTOR_M(x) (((x) >> 0) & 0x3) 644 #define CCU_PLL6_FACTOR_M_MASK (0x3 << 0) 645 #define CCU_PLL6_FACTOR_M_SHIFT 0 646 647 uint32_t 648 sxiccmu_pll6_get_frequency(void *cookie, uint32_t *cells) 649 { 650 struct sxiccmu_clock *sc = cookie; 651 uint32_t reg, k, m, n, freq; 652 uint32_t idx = cells[0]; 653 654 /* XXX Assume bypass is disabled. */ 655 reg = SXIREAD4(sc, 0); 656 k = CCU_PLL6_FACTOR_K(reg) + 1; 657 m = CCU_PLL6_FACTOR_M(reg) + 1; 658 n = CCU_PLL6_FACTOR_N(reg); 659 660 freq = clock_get_frequency_idx(sc->sc_node, 0); 661 switch (idx) { 662 case 0: 663 return (freq * n * k) / m / 6; /* pll6_sata */ 664 case 1: 665 return (freq * n * k) / 2; /* pll6_other */ 666 case 2: 667 return (freq * n * k); /* pll6 */ 668 case 3: 669 return (freq * n * k) / 4; /* pll6_div_4 */ 670 } 671 672 return 0; 673 } 674 675 void 676 sxiccmu_pll6_enable(void *cookie, uint32_t *cells, int on) 677 { 678 struct sxiccmu_clock *sc = cookie; 679 uint32_t idx = cells[0]; 680 uint32_t reg; 681 682 /* 683 * Since this clock has several outputs, we never turn it off. 684 */ 685 686 reg = SXIREAD4(sc, 0); 687 switch (idx) { 688 case 0: /* pll6_sata */ 689 if (on) 690 reg |= CCU_PLL6_SATA_CLK_EN; 691 else 692 reg &= ~CCU_PLL6_SATA_CLK_EN; 693 /* FALLTHROUGH */ 694 case 1: /* pll6_other */ 695 case 2: /* pll6 */ 696 case 3: /* pll6_div_4 */ 697 if (on) 698 reg |= CCU_PLL6_ENABLE; 699 } 700 SXIWRITE4(sc, 0, reg); 701 } 702 703 #define CCU_APB1_CLK_RAT_N(x) (((x) >> 16) & 0x3) 704 #define CCU_APB1_CLK_RAT_M(x) (((x) >> 0) & 0x1f) 705 #define CCU_APB1_CLK_SRC_SEL(x) (((x) >> 24) & 0x3) 706 707 uint32_t 708 sxiccmu_apb1_get_frequency(void *cookie, uint32_t *cells) 709 { 710 struct sxiccmu_clock *sc = cookie; 711 uint32_t reg, m, n, freq; 712 int idx; 713 714 reg = SXIREAD4(sc, 0); 715 m = CCU_APB1_CLK_RAT_M(reg); 716 n = CCU_APB1_CLK_RAT_N(reg); 717 idx = CCU_APB1_CLK_SRC_SEL(reg); 718 719 freq = clock_get_frequency_idx(sc->sc_node, idx); 720 return freq / (1 << n) / (m + 1); 721 } 722 723 #define CCU_CPUS_CLK_SRC_SEL(x) (((x) >> 16) & 0x3) 724 #define CCU_CPUS_POST_DIV(x) (((x) >> 8) & 0x1f) 725 #define CCU_CPUS_CLK_RATIO(x) (((x) >> 0) & 0x3) 726 727 uint32_t 728 sxiccmu_cpus_get_frequency(void *cookie, uint32_t *cells) 729 { 730 struct sxiccmu_clock *sc = cookie; 731 uint32_t reg, post_div, clk_ratio, freq; 732 int idx; 733 734 reg = SXIREAD4(sc, 0); 735 idx = CCU_CPUS_CLK_SRC_SEL(reg); 736 post_div = (idx == 2 ? CCU_CPUS_POST_DIV(reg): 0); 737 clk_ratio = CCU_CPUS_CLK_RATIO(reg); 738 739 freq = clock_get_frequency_idx(sc->sc_node, idx); 740 return freq / (clk_ratio + 1) / (post_div + 1); 741 } 742 743 #define CCU_APBS_CLK_RATIO(x) (((x) >> 0) & 0x3) 744 745 uint32_t 746 sxiccmu_apbs_get_frequency(void *cookie, uint32_t *cells) 747 { 748 struct sxiccmu_clock *sc = cookie; 749 uint32_t reg, freq; 750 751 reg = SXIREAD4(sc, 0); 752 freq = clock_get_frequency(sc->sc_node, NULL); 753 return freq / (CCU_APBS_CLK_RATIO(reg) + 1); 754 } 755 756 #define CCU_GMAC_CLK_PIT (1 << 2) 757 #define CCU_GMAC_CLK_TCS (3 << 0) 758 #define CCU_GMAC_CLK_TCS_MII 0 759 #define CCU_GMAC_CLK_TCS_EXT_125 1 760 #define CCU_GMAC_CLK_TCS_INT_RGMII 2 761 762 int 763 sxiccmu_gmac_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 764 { 765 struct sxiccmu_clock *sc = cookie; 766 767 switch (freq) { 768 case 25000000: /* MMI, 25 MHz */ 769 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 770 CCU_GMAC_CLK_TCS_MII); 771 break; 772 case 125000000: /* RGMII, 125 MHz */ 773 SXICMS4(sc, 0, CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS, 774 CCU_GMAC_CLK_PIT|CCU_GMAC_CLK_TCS_INT_RGMII); 775 break; 776 default: 777 return -1; 778 } 779 780 return 0; 781 } 782 783 #define CCU_SDx_SCLK_GATING (1U << 31) 784 #define CCU_SDx_CLK_SRC_SEL_OSC24M (0 << 24) 785 #define CCU_SDx_CLK_SRC_SEL_PLL6 (1 << 24) 786 #define CCU_SDx_CLK_SRC_SEL_PLL5 (2 << 24) 787 #define CCU_SDx_CLK_SRC_SEL_MASK (3 << 24) 788 #define CCU_SDx_CLK_DIV_RATIO_N_MASK (3 << 16) 789 #define CCU_SDx_CLK_DIV_RATIO_N_SHIFT 16 790 #define CCU_SDx_CLK_DIV_RATIO_M_MASK (7 << 0) 791 #define CCU_SDx_CLK_DIV_RATIO_M_SHIFT 0 792 793 int 794 sxiccmu_mmc_do_set_frequency(struct sxiccmu_clock *sc, uint32_t freq, 795 uint32_t parent_freq) 796 { 797 uint32_t reg, m, n; 798 uint32_t clk_src; 799 800 switch (freq) { 801 case 400000: 802 n = 2, m = 15; 803 clk_src = CCU_SDx_CLK_SRC_SEL_OSC24M; 804 break; 805 case 20000000: 806 case 25000000: 807 case 26000000: 808 case 50000000: 809 case 52000000: 810 n = 0, m = 0; 811 clk_src = CCU_SDx_CLK_SRC_SEL_PLL6; 812 while ((parent_freq / (1 << n) / 16) > freq) 813 n++; 814 while ((parent_freq / (1 << n) / (m + 1)) > freq) 815 m++; 816 break; 817 default: 818 return -1; 819 } 820 821 reg = SXIREAD4(sc, 0); 822 reg &= ~CCU_SDx_CLK_SRC_SEL_MASK; 823 reg |= clk_src; 824 reg &= ~CCU_SDx_CLK_DIV_RATIO_N_MASK; 825 reg |= n << CCU_SDx_CLK_DIV_RATIO_N_SHIFT; 826 reg &= ~CCU_SDx_CLK_DIV_RATIO_M_MASK; 827 reg |= m << CCU_SDx_CLK_DIV_RATIO_M_SHIFT; 828 SXIWRITE4(sc, 0, reg); 829 830 return 0; 831 } 832 833 int 834 sxiccmu_mmc_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 835 { 836 struct sxiccmu_clock *sc = cookie; 837 uint32_t parent_freq; 838 839 if (cells[0] != 0) 840 return -1; 841 842 parent_freq = clock_get_frequency_idx(sc->sc_node, 1); 843 return sxiccmu_mmc_do_set_frequency(sc, freq, parent_freq); 844 } 845 846 void 847 sxiccmu_mmc_enable(void *cookie, uint32_t *cells, int on) 848 { 849 struct sxiccmu_clock *sc = cookie; 850 851 if (cells[0] != 0) 852 return; 853 854 if (on) 855 SXISET4(sc, 0, CCU_SDx_SCLK_GATING); 856 else 857 SXICLR4(sc, 0, CCU_SDx_SCLK_GATING); 858 } 859 860 void 861 sxiccmu_gate_enable(void *cookie, uint32_t *cells, int on) 862 { 863 struct sxiccmu_clock *sc = cookie; 864 int reg = cells[0] / 32; 865 int bit = cells[0] % 32; 866 867 if (on) { 868 clock_enable(sc->sc_node, NULL); 869 SXISET4(sc, reg * 4, (1U << bit)); 870 } else { 871 SXICLR4(sc, reg * 4, (1U << bit)); 872 clock_disable(sc->sc_node, NULL); 873 } 874 } 875 876 void 877 sxiccmu_reset(void *cookie, uint32_t *cells, int assert) 878 { 879 struct sxiccmu_clock *sc = cookie; 880 int reg = cells[0] / 32; 881 int bit = cells[0] % 32; 882 883 if (assert) 884 SXICLR4(sc, reg * 4, (1U << bit)); 885 else 886 SXISET4(sc, reg * 4, (1U << bit)); 887 } 888 889 /* 890 * Newer device trees, such as those for the Allwinner H3/A64 have 891 * most of the clock nodes replaced with a single clock control unit 892 * node. 893 */ 894 895 uint32_t 896 sxiccmu_ccu_get_frequency(void *cookie, uint32_t *cells) 897 { 898 struct sxiccmu_softc *sc = cookie; 899 uint32_t idx = cells[0]; 900 uint32_t parent; 901 902 if (idx < sc->sc_ngates && sc->sc_gates[idx].parent) { 903 parent = sc->sc_gates[idx].parent; 904 return sxiccmu_ccu_get_frequency(sc, &parent); 905 } 906 907 return sc->sc_get_frequency(sc, idx); 908 } 909 910 /* Allwinner A10/A20 */ 911 #define A10_PLL1_CFG_REG 0x0000 912 #define A10_PLL1_OUT_EXT_DIVP_MASK (0x3 << 16) 913 #define A10_PLL1_OUT_EXT_DIVP_SHIFT 16 914 #define A10_PLL1_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) 915 #define A10_PLL1_FACTOR_N(x) (((x) >> 8) & 0x1f) 916 #define A10_PLL1_FACTOR_N_MASK (0x1f << 8) 917 #define A10_PLL1_FACTOR_N_SHIFT 8 918 #define A10_PLL1_FACTOR_K(x) (((x) >> 4) & 0x3) 919 #define A10_PLL1_FACTOR_K_MASK (0x3 << 4) 920 #define A10_PLL1_FACTOR_K_SHIFT 4 921 #define A10_PLL1_FACTOR_M(x) (((x) >> 0) & 0x3) 922 #define A10_PLL1_FACTOR_M_MASK (0x3 << 0) 923 #define A10_PLL1_FACTOR_M_SHIFT 0 924 #define A10_CPU_AHB_APB0_CFG_REG 0x0054 925 #define A10_CPU_CLK_SRC_SEL (0x3 << 16) 926 #define A10_CPU_CLK_SRC_SEL_LOSC (0x0 << 16) 927 #define A10_CPU_CLK_SRC_SEL_OSC24M (0x1 << 16) 928 #define A10_CPU_CLK_SRC_SEL_PLL1 (0x2 << 16) 929 #define A10_CPU_CLK_SRC_SEL_200MHZ (0x3 << 16) 930 #define A10_AHB_CLK_DIV_RATIO(x) (((x) >> 8) & 0x3) 931 #define A10_AXI_CLK_DIV_RATIO(x) (((x) >> 0) & 0x3) 932 933 uint32_t 934 sxiccmu_a10_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 935 { 936 uint32_t parent; 937 uint32_t reg, div; 938 uint32_t k, m, n, p; 939 940 switch (idx) { 941 case A10_CLK_LOSC: 942 return clock_get_frequency(sc->sc_node, "losc"); 943 case A10_CLK_HOSC: 944 return clock_get_frequency(sc->sc_node, "hosc"); 945 case A10_CLK_PLL_CORE: 946 reg = SXIREAD4(sc, A10_PLL1_CFG_REG); 947 k = A10_PLL1_FACTOR_K(reg) + 1; 948 m = A10_PLL1_FACTOR_M(reg) + 1; 949 n = A10_PLL1_FACTOR_N(reg); 950 p = 1 << A10_PLL1_OUT_EXT_DIVP(reg); 951 return (24000000 * n * k) / (m * p); 952 case A10_CLK_PLL_PERIPH_BASE: 953 /* Not hardcoded, but recommended. */ 954 return 600000000; 955 case A10_CLK_PLL_PERIPH: 956 return sxiccmu_a10_get_frequency(sc, A10_CLK_PLL_PERIPH_BASE) * 2; 957 case A10_CLK_CPU: 958 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 959 switch (reg & A10_CPU_CLK_SRC_SEL) { 960 case A10_CPU_CLK_SRC_SEL_LOSC: 961 parent = A10_CLK_LOSC; 962 break; 963 case A10_CPU_CLK_SRC_SEL_OSC24M: 964 parent = A10_CLK_HOSC; 965 break; 966 case A10_CPU_CLK_SRC_SEL_PLL1: 967 parent = A10_CLK_PLL_CORE; 968 break; 969 case A10_CPU_CLK_SRC_SEL_200MHZ: 970 return 200000000; 971 } 972 return sxiccmu_ccu_get_frequency(sc, &parent); 973 case A10_CLK_AXI: 974 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 975 div = 1 << A10_AXI_CLK_DIV_RATIO(reg); 976 parent = A10_CLK_CPU; 977 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 978 case A10_CLK_AHB: 979 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 980 div = 1 << A10_AHB_CLK_DIV_RATIO(reg); 981 parent = A10_CLK_AXI; 982 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 983 case A10_CLK_APB1: 984 /* XXX Controlled by a MUX. */ 985 return 24000000; 986 } 987 988 printf("%s: 0x%08x\n", __func__, idx); 989 return 0; 990 } 991 992 /* Allwinner A23/A64/H3/H5/R40 */ 993 #define CCU_AHB1_APB1_CFG_REG 0x0054 994 #define CCU_AHB1_CLK_SRC_SEL (3 << 12) 995 #define CCU_AHB1_CLK_SRC_SEL_LOSC (0 << 12) 996 #define CCU_AHB1_CLK_SRC_SEL_OSC24M (1 << 12) 997 #define CCU_AHB1_CLK_SRC_SEL_AXI (2 << 12) 998 #define CCU_AHB1_CLK_SRC_SEL_PERIPH0 (3 << 12) 999 #define CCU_AHB1_PRE_DIV(x) ((((x) >> 6) & 3) + 1) 1000 #define CCU_AHB1_CLK_DIV_RATIO(x) (1 << (((x) >> 4) & 3)) 1001 #define CCU_AHB2_CFG_REG 0x005c 1002 #define CCU_AHB2_CLK_CFG (3 << 0) 1003 1004 uint32_t 1005 sxiccmu_a23_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1006 { 1007 uint32_t parent; 1008 uint32_t reg, div; 1009 1010 switch (idx) { 1011 case A23_CLK_LOSC: 1012 return clock_get_frequency(sc->sc_node, "losc"); 1013 case A23_CLK_HOSC: 1014 return clock_get_frequency(sc->sc_node, "hosc"); 1015 case A23_CLK_PLL_PERIPH: 1016 /* Not hardcoded, but recommended. */ 1017 return 600000000; 1018 case A23_CLK_APB2: 1019 /* XXX Controlled by a MUX. */ 1020 return 24000000; 1021 case A23_CLK_AHB1: 1022 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1023 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1024 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1025 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1026 parent = A23_CLK_LOSC; 1027 break; 1028 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1029 parent = A23_CLK_HOSC; 1030 break; 1031 case CCU_AHB1_CLK_SRC_SEL_AXI: 1032 parent = A23_CLK_AXI; 1033 break; 1034 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1035 parent = A23_CLK_PLL_PERIPH; 1036 div *= CCU_AHB1_PRE_DIV(reg); 1037 break; 1038 default: 1039 return 0; 1040 } 1041 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1042 } 1043 1044 printf("%s: 0x%08x\n", __func__, idx); 1045 return 0; 1046 } 1047 1048 #define A64_PLL_CPUX_CTRL_REG 0x0000 1049 #define A64_PLL_CPUX_LOCK (1 << 28) 1050 #define A64_PLL_CPUX_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) 1051 #define A64_PLL_CPUX_OUT_EXT_DIVP_MASK (0x3 << 16) 1052 #define A64_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f) 1053 #define A64_PLL_CPUX_FACTOR_N_MASK (0x1f << 8) 1054 #define A64_PLL_CPUX_FACTOR_N_SHIFT 8 1055 #define A64_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3) 1056 #define A64_PLL_CPUX_FACTOR_K_MASK (0x3 << 4) 1057 #define A64_PLL_CPUX_FACTOR_K_SHIFT 4 1058 #define A64_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3) 1059 #define A64_PLL_CPUX_FACTOR_M_MASK (0x3 << 0) 1060 #define A64_CPUX_AXI_CFG_REG 0x0050 1061 #define A64_CPUX_CLK_SRC_SEL (0x3 << 16) 1062 #define A64_CPUX_CLK_SRC_SEL_LOSC (0x0 << 16) 1063 #define A64_CPUX_CLK_SRC_SEL_OSC24M (0x1 << 16) 1064 #define A64_CPUX_CLK_SRC_SEL_PLL_CPUX (0x2 << 16) 1065 1066 uint32_t 1067 sxiccmu_a64_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1068 { 1069 uint32_t parent; 1070 uint32_t reg, div; 1071 uint32_t k, m, n, p; 1072 1073 switch (idx) { 1074 case A64_CLK_PLL_CPUX: 1075 reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG); 1076 k = A64_PLL_CPUX_FACTOR_K(reg) + 1; 1077 m = A64_PLL_CPUX_FACTOR_M(reg) + 1; 1078 n = A64_PLL_CPUX_FACTOR_N(reg) + 1; 1079 p = 1 << A64_PLL_CPUX_OUT_EXT_DIVP(reg); 1080 return (24000000 * n * k) / (m * p); 1081 case A64_CLK_CPUX: 1082 reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG); 1083 switch (reg & A64_CPUX_CLK_SRC_SEL) { 1084 case A64_CPUX_CLK_SRC_SEL_LOSC: 1085 parent = A64_CLK_LOSC; 1086 break; 1087 case A64_CPUX_CLK_SRC_SEL_OSC24M: 1088 parent = A64_CLK_HOSC; 1089 break; 1090 case A64_CPUX_CLK_SRC_SEL_PLL_CPUX: 1091 parent = A64_CLK_PLL_CPUX; 1092 break; 1093 default: 1094 return 0; 1095 } 1096 return sxiccmu_ccu_get_frequency(sc, &parent); 1097 case A64_CLK_LOSC: 1098 return clock_get_frequency(sc->sc_node, "losc"); 1099 case A64_CLK_HOSC: 1100 return clock_get_frequency(sc->sc_node, "hosc"); 1101 case A64_CLK_PLL_PERIPH0: 1102 /* Not hardcoded, but recommended. */ 1103 return 600000000; 1104 case A64_CLK_PLL_PERIPH0_2X: 1105 return sxiccmu_a64_get_frequency(sc, A64_CLK_PLL_PERIPH0) * 2; 1106 case A64_CLK_APB2: 1107 /* XXX Controlled by a MUX. */ 1108 return 24000000; 1109 case A64_CLK_AHB1: 1110 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1111 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1112 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1113 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1114 parent = A64_CLK_LOSC; 1115 break; 1116 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1117 parent = A64_CLK_HOSC; 1118 break; 1119 case CCU_AHB1_CLK_SRC_SEL_AXI: 1120 parent = A64_CLK_AXI; 1121 break; 1122 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1123 parent = A64_CLK_PLL_PERIPH0; 1124 div *= CCU_AHB1_PRE_DIV(reg); 1125 break; 1126 default: 1127 return 0; 1128 } 1129 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1130 case A64_CLK_AHB2: 1131 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 1132 switch (reg & CCU_AHB2_CLK_CFG) { 1133 case 0: 1134 parent = A64_CLK_AHB1; 1135 div = 1; 1136 break; 1137 case 1: 1138 parent = A64_CLK_PLL_PERIPH0; 1139 div = 2; 1140 break; 1141 default: 1142 return 0; 1143 } 1144 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1145 } 1146 1147 printf("%s: 0x%08x\n", __func__, idx); 1148 return 0; 1149 } 1150 1151 #define A80_AHB1_CLK_CFG_REG 0x0064 1152 #define A80_AHB1_SRC_CLK_SELECT (3 << 24) 1153 #define A80_AHB1_SRC_CLK_SELECT_GTBUS (0 << 24) 1154 #define A80_AHB1_SRC_CLK_SELECT_PERIPH0 (1 << 24) 1155 #define A80_AHB1_CLK_DIV_RATIO(x) (1 << ((x) & 0x3)) 1156 1157 uint32_t 1158 sxiccmu_a80_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1159 { 1160 uint32_t parent; 1161 uint32_t reg, div; 1162 1163 switch (idx) { 1164 case A80_CLK_PLL_PERIPH0: 1165 /* Not hardcoded, but recommended. */ 1166 return 960000000; 1167 case A80_CLK_AHB1: 1168 reg = SXIREAD4(sc, A80_AHB1_CLK_CFG_REG); 1169 div = A80_AHB1_CLK_DIV_RATIO(reg); 1170 switch (reg & A80_AHB1_SRC_CLK_SELECT) { 1171 case A80_AHB1_SRC_CLK_SELECT_GTBUS: 1172 parent = A80_CLK_GTBUS; 1173 break; 1174 case A80_AHB1_SRC_CLK_SELECT_PERIPH0: 1175 parent = A80_CLK_PLL_PERIPH0; 1176 break; 1177 default: 1178 parent = A80_CLK_PLL_PERIPH1; 1179 break; 1180 } 1181 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1182 case A80_CLK_APB1: 1183 /* XXX Controlled by a MUX. */ 1184 return 24000000; 1185 } 1186 1187 printf("%s: 0x%08x\n", __func__, idx); 1188 return 0; 1189 } 1190 1191 /* Allwinner D1 */ 1192 #define D1_PLL_CPU_CTRL_REG 0x0000 1193 #define D1_PLL_CPU_FACTOR_M(x) (((x) >> 0) & 0x3) 1194 #define D1_PLL_CPU_FACTOR_N(x) (((x) >> 8) & 0xff) 1195 #define D1_RISCV_CLK_REG 0x0d00 1196 #define D1_RISCV_CLK_SEL (7 << 24) 1197 #define D1_RISCV_CLK_SEL_HOSC (0 << 24) 1198 #define D1_RISCV_CLK_SEL_PLL_CPU (5 << 24) 1199 #define D1_RISCV_DIV_CFG_FACTOR_M(x) (((x) >> 0) & 0x1f) 1200 1201 uint32_t 1202 sxiccmu_d1_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1203 { 1204 uint32_t parent; 1205 uint32_t reg; 1206 uint32_t m, n; 1207 1208 switch (idx) { 1209 case D1_CLK_HOSC: 1210 return clock_get_frequency(sc->sc_node, "hosc"); 1211 case D1_CLK_PLL_CPU: 1212 reg = SXIREAD4(sc, D1_PLL_CPU_CTRL_REG); 1213 m = D1_PLL_CPU_FACTOR_M(reg) + 1; 1214 n = D1_PLL_CPU_FACTOR_N(reg) + 1; 1215 return (24000000 * n) / m; 1216 case D1_CLK_PLL_PERIPH0: 1217 /* Not hardcoded, but recommended. */ 1218 return 600000000; 1219 case D1_CLK_APB1: 1220 /* XXX Controlled by a MUX. */ 1221 return 24000000; 1222 case D1_CLK_RISCV: 1223 reg = SXIREAD4(sc, D1_RISCV_CLK_REG); 1224 switch (reg & D1_RISCV_CLK_SEL) { 1225 case D1_RISCV_CLK_SEL_HOSC: 1226 parent = D1_CLK_HOSC; 1227 break; 1228 case D1_RISCV_CLK_SEL_PLL_CPU: 1229 parent = D1_CLK_PLL_CPU; 1230 break; 1231 default: 1232 return 0; 1233 } 1234 m = D1_RISCV_DIV_CFG_FACTOR_M(reg) + 1; 1235 return sxiccmu_ccu_get_frequency(sc, &parent) / m; 1236 } 1237 1238 printf("%s: 0x%08x\n", __func__, idx); 1239 return 0; 1240 } 1241 1242 /* Allwinner H3/H5 */ 1243 #define H3_PLL_CPUX_CTRL_REG 0x0000 1244 #define H3_PLL_CPUX_ENABLE (1U << 31) 1245 #define H3_PLL_CPUX_LOCK (1 << 28) 1246 #define H3_PLL_CPUX_OUT_EXT_DIVP(x) (((x) >> 16) & 0x3) 1247 #define H3_PLL_CPUX_OUT_EXT_DIVP_MASK (0x3 << 16) 1248 #define H3_PLL_CPUX_OUT_EXT_DIVP_SHIFT 16 1249 #define H3_PLL_CPUX_FACTOR_N(x) (((x) >> 8) & 0x1f) 1250 #define H3_PLL_CPUX_FACTOR_N_MASK (0x1f << 8) 1251 #define H3_PLL_CPUX_FACTOR_N_SHIFT 8 1252 #define H3_PLL_CPUX_FACTOR_K(x) (((x) >> 4) & 0x3) 1253 #define H3_PLL_CPUX_FACTOR_K_MASK (0x3 << 4) 1254 #define H3_PLL_CPUX_FACTOR_K_SHIFT 4 1255 #define H3_PLL_CPUX_FACTOR_M(x) (((x) >> 0) & 0x3) 1256 #define H3_PLL_CPUX_FACTOR_M_MASK (0x3 << 0) 1257 #define H3_PLL_CPUX_FACTOR_M_SHIFT 0 1258 #define H3_CPUX_AXI_CFG_REG 0x0050 1259 #define H3_CPUX_CLK_SRC_SEL (0x3 << 16) 1260 #define H3_CPUX_CLK_SRC_SEL_LOSC (0x0 << 16) 1261 #define H3_CPUX_CLK_SRC_SEL_OSC24M (0x1 << 16) 1262 #define H3_CPUX_CLK_SRC_SEL_PLL_CPUX (0x2 << 16) 1263 #define H3_PLL_STABLE_TIME_REG1 0x0204 1264 #define H3_PLL_STABLE_TIME_REG1_TIME(x) (((x) >> 0) & 0xffff) 1265 1266 uint32_t 1267 sxiccmu_h3_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1268 { 1269 uint32_t parent; 1270 uint32_t reg, div; 1271 uint32_t k, m, n, p; 1272 1273 switch (idx) { 1274 case H3_CLK_LOSC: 1275 return clock_get_frequency(sc->sc_node, "losc"); 1276 case H3_CLK_HOSC: 1277 return clock_get_frequency(sc->sc_node, "hosc"); 1278 case H3_CLK_PLL_CPUX: 1279 reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG); 1280 k = H3_PLL_CPUX_FACTOR_K(reg) + 1; 1281 m = H3_PLL_CPUX_FACTOR_M(reg) + 1; 1282 n = H3_PLL_CPUX_FACTOR_N(reg) + 1; 1283 p = 1 << H3_PLL_CPUX_OUT_EXT_DIVP(reg); 1284 return (24000000 * n * k) / (m * p); 1285 case H3_CLK_PLL_PERIPH0: 1286 /* Not hardcoded, but recommended. */ 1287 return 600000000; 1288 case H3_CLK_CPUX: 1289 reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG); 1290 switch (reg & H3_CPUX_CLK_SRC_SEL) { 1291 case H3_CPUX_CLK_SRC_SEL_LOSC: 1292 parent = H3_CLK_LOSC; 1293 break; 1294 case H3_CPUX_CLK_SRC_SEL_OSC24M: 1295 parent = H3_CLK_HOSC; 1296 break; 1297 case H3_CPUX_CLK_SRC_SEL_PLL_CPUX: 1298 parent = H3_CLK_PLL_CPUX; 1299 break; 1300 default: 1301 return 0; 1302 } 1303 return sxiccmu_ccu_get_frequency(sc, &parent); 1304 case H3_CLK_APB2: 1305 /* XXX Controlled by a MUX. */ 1306 return 24000000; 1307 case H3_CLK_AHB1: 1308 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1309 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1310 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1311 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1312 parent = H3_CLK_LOSC; 1313 break; 1314 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1315 parent = H3_CLK_HOSC; 1316 break; 1317 case CCU_AHB1_CLK_SRC_SEL_AXI: 1318 parent = H3_CLK_AXI; 1319 break; 1320 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1321 parent = H3_CLK_PLL_PERIPH0; 1322 div *= CCU_AHB1_PRE_DIV(reg); 1323 break; 1324 default: 1325 return 0; 1326 } 1327 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1328 case H3_CLK_AHB2: 1329 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 1330 switch (reg & CCU_AHB2_CLK_CFG) { 1331 case 0: 1332 parent = H3_CLK_AHB1; 1333 div = 1; 1334 break; 1335 case 1: 1336 parent = H3_CLK_PLL_PERIPH0; 1337 div = 2; 1338 break; 1339 default: 1340 return 0; 1341 } 1342 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1343 } 1344 1345 printf("%s: 0x%08x\n", __func__, idx); 1346 return 0; 1347 } 1348 1349 #define H3_AHB0_CLK_REG 0x0000 1350 #define H3_AHB0_CLK_SRC_SEL (0x3 << 16) 1351 #define H3_AHB0_CLK_SRC_SEL_OSC32K (0x0 << 16) 1352 #define H3_AHB0_CLK_SRC_SEL_OSC24M (0x1 << 16) 1353 #define H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0 (0x2 << 16) 1354 #define H3_AHB0_CLK_SRC_SEL_IOSC (0x3 << 16) 1355 #define H3_AHB0_CLK_PRE_DIV(x) ((((x) >> 8) & 0x1f) + 1) 1356 #define H3_AHB0_CLK_RATIO(x) (1 << (((x) >> 4) & 3)) 1357 #define H3_APB0_CFG_REG 0x000c 1358 #define H3_APB0_CLK_RATIO(x) (1 << ((x) & 1)) 1359 1360 uint32_t 1361 sxiccmu_h3_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1362 { 1363 uint32_t parent; 1364 uint32_t reg, div; 1365 uint32_t freq; 1366 1367 switch (idx) { 1368 case H3_R_CLK_AHB0: 1369 reg = SXIREAD4(sc, H3_AHB0_CLK_REG); 1370 switch (reg & H3_AHB0_CLK_SRC_SEL) { 1371 case H3_AHB0_CLK_SRC_SEL_OSC32K: 1372 freq = clock_get_frequency(sc->sc_node, "losc"); 1373 break; 1374 case H3_AHB0_CLK_SRC_SEL_OSC24M: 1375 freq = clock_get_frequency(sc->sc_node, "hosc"); 1376 break; 1377 case H3_AHB0_CLK_SRC_SEL_PLL_PERIPH0: 1378 freq = clock_get_frequency(sc->sc_node, "pll-periph"); 1379 break; 1380 case H3_AHB0_CLK_SRC_SEL_IOSC: 1381 freq = clock_get_frequency(sc->sc_node, "iosc"); 1382 break; 1383 } 1384 div = H3_AHB0_CLK_PRE_DIV(reg) * H3_AHB0_CLK_RATIO(reg); 1385 return freq / div; 1386 case H3_R_CLK_APB0: 1387 reg = SXIREAD4(sc, H3_APB0_CFG_REG); 1388 div = H3_APB0_CLK_RATIO(reg); 1389 parent = H3_R_CLK_AHB0; 1390 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1391 } 1392 1393 printf("%s: 0x%08x\n", __func__, idx); 1394 return 0; 1395 } 1396 1397 /* Allwinner H6 */ 1398 #define H6_AHB3_CFG_REG 0x051c 1399 #define H6_AHB3_CLK_FACTOR_N(x) (((x) >> 8) & 0x3) 1400 #define H6_AHB3_CLK_FACTOR_M(x) (((x) >> 0) & 0x3) 1401 1402 uint32_t 1403 sxiccmu_h6_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1404 { 1405 uint32_t reg, m, n; 1406 uint32_t freq; 1407 1408 switch (idx) { 1409 case H6_CLK_PLL_PERIPH0: 1410 /* Not hardcoded, but recommended. */ 1411 return 600000000; 1412 case H6_CLK_PLL_PERIPH0_2X: 1413 return sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0) * 2; 1414 case H6_CLK_AHB3: 1415 reg = SXIREAD4(sc, H6_AHB3_CFG_REG); 1416 /* assume PLL_PERIPH0 source */ 1417 freq = sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0); 1418 m = H6_AHB3_CLK_FACTOR_M(reg) + 1; 1419 n = 1 << H6_AHB3_CLK_FACTOR_N(reg); 1420 return freq / (m * n); 1421 case H6_CLK_APB2: 1422 /* XXX Controlled by a MUX. */ 1423 return 24000000; 1424 } 1425 1426 printf("%s: 0x%08x\n", __func__, idx); 1427 return 0; 1428 } 1429 1430 uint32_t 1431 sxiccmu_h6_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1432 { 1433 switch (idx) { 1434 case H6_R_CLK_APB2: 1435 /* XXX Controlled by a MUX. */ 1436 return 24000000; 1437 } 1438 1439 printf("%s: 0x%08x\n", __func__, idx); 1440 return 0; 1441 } 1442 1443 /* Allwinner H616 */ 1444 #define H616_AHB3_CFG_REG 0x051c 1445 #define H616_AHB3_CLK_FACTOR_N(x) (((x) >> 8) & 0x3) 1446 #define H616_AHB3_CLK_FACTOR_M(x) (((x) >> 0) & 0x3) 1447 1448 uint32_t 1449 sxiccmu_h616_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1450 { 1451 uint32_t reg, m, n; 1452 uint32_t freq; 1453 1454 switch (idx) { 1455 case H616_CLK_PLL_PERIPH0: 1456 /* Not hardcoded, but recommended. */ 1457 return 600000000; 1458 case H616_CLK_PLL_PERIPH0_2X: 1459 return sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0) * 2; 1460 case H616_CLK_AHB3: 1461 reg = SXIREAD4(sc, H616_AHB3_CFG_REG); 1462 /* assume PLL_PERIPH0 source */ 1463 freq = sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0); 1464 m = H616_AHB3_CLK_FACTOR_M(reg) + 1; 1465 n = 1 << H616_AHB3_CLK_FACTOR_N(reg); 1466 return freq / (m * n); 1467 case H616_CLK_APB2: 1468 /* XXX Controlled by a MUX. */ 1469 return 24000000; 1470 } 1471 1472 printf("%s: 0x%08x\n", __func__, idx); 1473 return 0; 1474 } 1475 1476 uint32_t 1477 sxiccmu_h616_r_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1478 { 1479 switch (idx) { 1480 case H616_R_CLK_APB2: 1481 /* XXX Controlled by a MUX. */ 1482 return 24000000; 1483 } 1484 1485 printf("%s: 0x%08x\n", __func__, idx); 1486 return 0; 1487 } 1488 1489 uint32_t 1490 sxiccmu_r40_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1491 { 1492 uint32_t parent; 1493 uint32_t reg, div; 1494 1495 switch (idx) { 1496 case R40_CLK_LOSC: 1497 return clock_get_frequency(sc->sc_node, "losc"); 1498 case R40_CLK_HOSC: 1499 return clock_get_frequency(sc->sc_node, "hosc"); 1500 case R40_CLK_PLL_PERIPH0: 1501 /* Not hardcoded, but recommended. */ 1502 return 600000000; 1503 case R40_CLK_PLL_PERIPH0_2X: 1504 return sxiccmu_r40_get_frequency(sc, R40_CLK_PLL_PERIPH0) * 2; 1505 case R40_CLK_AHB1: 1506 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1507 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1508 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1509 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1510 parent = R40_CLK_LOSC; 1511 break; 1512 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1513 parent = R40_CLK_HOSC; 1514 break; 1515 case CCU_AHB1_CLK_SRC_SEL_AXI: 1516 parent = R40_CLK_AXI; 1517 break; 1518 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1519 parent = R40_CLK_PLL_PERIPH0; 1520 div *= CCU_AHB1_PRE_DIV(reg); 1521 break; 1522 } 1523 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1524 case R40_CLK_APB2: 1525 /* XXX Controlled by a MUX. */ 1526 return 24000000; 1527 } 1528 1529 printf("%s: 0x%08x\n", __func__, idx); 1530 return 0; 1531 } 1532 1533 uint32_t 1534 sxiccmu_v3s_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1535 { 1536 uint32_t parent; 1537 uint32_t reg, div; 1538 1539 switch (idx) { 1540 case V3S_CLK_LOSC: 1541 return clock_get_frequency(sc->sc_node, "losc"); 1542 case V3S_CLK_HOSC: 1543 return clock_get_frequency(sc->sc_node, "hosc"); 1544 case V3S_CLK_PLL_PERIPH0: 1545 /* Not hardcoded, but recommended. */ 1546 return 600000000; 1547 case V3S_CLK_APB2: 1548 /* XXX Controlled by a MUX. */ 1549 return 24000000; 1550 case V3S_CLK_AHB1: 1551 reg = SXIREAD4(sc, CCU_AHB1_APB1_CFG_REG); 1552 div = CCU_AHB1_CLK_DIV_RATIO(reg); 1553 switch (reg & CCU_AHB1_CLK_SRC_SEL) { 1554 case CCU_AHB1_CLK_SRC_SEL_LOSC: 1555 parent = V3S_CLK_LOSC; 1556 break; 1557 case CCU_AHB1_CLK_SRC_SEL_OSC24M: 1558 parent = V3S_CLK_HOSC; 1559 break; 1560 case CCU_AHB1_CLK_SRC_SEL_AXI: 1561 parent = V3S_CLK_AXI; 1562 break; 1563 case CCU_AHB1_CLK_SRC_SEL_PERIPH0: 1564 parent = V3S_CLK_PLL_PERIPH0; 1565 div *= CCU_AHB1_PRE_DIV(reg); 1566 break; 1567 default: 1568 return 0; 1569 } 1570 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1571 case V3S_CLK_AHB2: 1572 reg = SXIREAD4(sc, CCU_AHB2_CFG_REG); 1573 switch (reg & CCU_AHB2_CLK_CFG) { 1574 case 0: 1575 parent = V3S_CLK_AHB1; 1576 div = 1; 1577 break; 1578 case 1: 1579 parent = V3S_CLK_PLL_PERIPH0; 1580 div = 2; 1581 break; 1582 default: 1583 return 0; 1584 } 1585 return sxiccmu_ccu_get_frequency(sc, &parent) / div; 1586 } 1587 1588 printf("%s: 0x%08x\n", __func__, idx); 1589 return 0; 1590 } 1591 1592 uint32_t 1593 sxiccmu_nop_get_frequency(struct sxiccmu_softc *sc, uint32_t idx) 1594 { 1595 printf("%s: 0x%08x\n", __func__, idx); 1596 return 0; 1597 } 1598 1599 int 1600 sxiccmu_ccu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 1601 { 1602 struct sxiccmu_softc *sc = cookie; 1603 uint32_t idx = cells[0]; 1604 1605 return sc->sc_set_frequency(sc, idx, freq); 1606 } 1607 1608 int 1609 sxiccmu_a10_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1610 { 1611 struct sxiccmu_clock clock; 1612 uint32_t parent, parent_freq; 1613 uint32_t reg; 1614 int k, n; 1615 int error; 1616 1617 switch (idx) { 1618 case A10_CLK_PLL_CORE: 1619 k = 1; n = 32; 1620 while (k <= 4 && (24000000 * n * k) < freq) 1621 k++; 1622 while (n >= 1 && (24000000 * n * k) > freq) 1623 n--; 1624 1625 reg = SXIREAD4(sc, A10_PLL1_CFG_REG); 1626 reg &= ~A10_PLL1_OUT_EXT_DIVP_MASK; 1627 reg &= ~A10_PLL1_FACTOR_N_MASK; 1628 reg &= ~A10_PLL1_FACTOR_K_MASK; 1629 reg &= ~A10_PLL1_FACTOR_M_MASK; 1630 reg |= (n << A10_PLL1_FACTOR_N_SHIFT); 1631 reg |= ((k - 1) << A10_PLL1_FACTOR_K_SHIFT); 1632 SXIWRITE4(sc, A10_PLL1_CFG_REG, reg); 1633 1634 /* No need to wait PLL to lock? */ 1635 1636 return 0; 1637 case A10_CLK_CPU: 1638 /* Switch to 24 MHz clock. */ 1639 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 1640 reg &= ~A10_CPU_CLK_SRC_SEL; 1641 reg |= A10_CPU_CLK_SRC_SEL_OSC24M; 1642 SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg); 1643 1644 error = sxiccmu_a10_set_frequency(sc, A10_CLK_PLL_CORE, freq); 1645 1646 /* Switch back to PLL. */ 1647 reg = SXIREAD4(sc, A10_CPU_AHB_APB0_CFG_REG); 1648 reg &= ~A10_CPU_CLK_SRC_SEL; 1649 reg |= A10_CPU_CLK_SRC_SEL_PLL1; 1650 SXIWRITE4(sc, A10_CPU_AHB_APB0_CFG_REG, reg); 1651 return error; 1652 case A10_CLK_MMC0: 1653 case A10_CLK_MMC1: 1654 case A10_CLK_MMC2: 1655 case A10_CLK_MMC3: 1656 clock.sc_iot = sc->sc_iot; 1657 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1658 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1659 parent = A10_CLK_PLL_PERIPH; 1660 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1661 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1662 } 1663 1664 printf("%s: 0x%08x\n", __func__, idx); 1665 return -1; 1666 } 1667 1668 int 1669 sxiccmu_a23_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1670 { 1671 struct sxiccmu_clock clock; 1672 uint32_t parent, parent_freq; 1673 1674 switch (idx) { 1675 case A23_CLK_MMC0: 1676 case A23_CLK_MMC1: 1677 case A23_CLK_MMC2: 1678 clock.sc_iot = sc->sc_iot; 1679 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1680 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1681 parent = A23_CLK_PLL_PERIPH; 1682 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1683 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1684 } 1685 1686 printf("%s: 0x%08x\n", __func__, idx); 1687 return -1; 1688 } 1689 1690 int 1691 sxiccmu_a64_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1692 { 1693 struct sxiccmu_clock clock; 1694 uint32_t parent, parent_freq; 1695 uint32_t reg; 1696 int k, n; 1697 int error; 1698 1699 switch (idx) { 1700 case A64_CLK_PLL_CPUX: 1701 k = 1; n = 32; 1702 while (k <= 4 && (24000000 * n * k) < freq) 1703 k++; 1704 while (n >= 1 && (24000000 * n * k) > freq) 1705 n--; 1706 1707 reg = SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG); 1708 reg &= ~A64_PLL_CPUX_OUT_EXT_DIVP_MASK; 1709 reg &= ~A64_PLL_CPUX_FACTOR_N_MASK; 1710 reg &= ~A64_PLL_CPUX_FACTOR_K_MASK; 1711 reg &= ~A64_PLL_CPUX_FACTOR_M_MASK; 1712 reg |= ((n - 1) << A64_PLL_CPUX_FACTOR_N_SHIFT); 1713 reg |= ((k - 1) << A64_PLL_CPUX_FACTOR_K_SHIFT); 1714 SXIWRITE4(sc, A64_PLL_CPUX_CTRL_REG, reg); 1715 1716 /* Wait for PLL to lock. */ 1717 while ((SXIREAD4(sc, A64_PLL_CPUX_CTRL_REG) & 1718 A64_PLL_CPUX_LOCK) == 0) { 1719 delay(200); 1720 } 1721 1722 return 0; 1723 case A64_CLK_CPUX: 1724 /* Switch to 24 MHz clock. */ 1725 reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG); 1726 reg &= ~A64_CPUX_CLK_SRC_SEL; 1727 reg |= A64_CPUX_CLK_SRC_SEL_OSC24M; 1728 SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg); 1729 1730 error = sxiccmu_a64_set_frequency(sc, A64_CLK_PLL_CPUX, freq); 1731 1732 /* Switch back to PLL. */ 1733 reg = SXIREAD4(sc, A64_CPUX_AXI_CFG_REG); 1734 reg &= ~A64_CPUX_CLK_SRC_SEL; 1735 reg |= A64_CPUX_CLK_SRC_SEL_PLL_CPUX; 1736 SXIWRITE4(sc, A64_CPUX_AXI_CFG_REG, reg); 1737 return error; 1738 case A64_CLK_MMC0: 1739 case A64_CLK_MMC1: 1740 case A64_CLK_MMC2: 1741 clock.sc_iot = sc->sc_iot; 1742 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1743 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1744 parent = A64_CLK_PLL_PERIPH0_2X; 1745 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1746 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1747 } 1748 1749 printf("%s: 0x%08x\n", __func__, idx); 1750 return -1; 1751 } 1752 1753 int 1754 sxiccmu_a80_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1755 { 1756 struct sxiccmu_clock clock; 1757 uint32_t parent, parent_freq; 1758 1759 switch (idx) { 1760 case A80_CLK_MMC0: 1761 case A80_CLK_MMC1: 1762 case A80_CLK_MMC2: 1763 clock.sc_iot = sc->sc_iot; 1764 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1765 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1766 parent = A80_CLK_PLL_PERIPH0; 1767 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1768 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1769 } 1770 1771 printf("%s: 0x%08x\n", __func__, idx); 1772 return -1; 1773 } 1774 1775 #define D1_SMHC0_CLK_REG 0x0830 1776 #define D1_SMHC1_CLK_REG 0x0834 1777 #define D1_SMHC2_CLK_REG 0x0838 1778 #define D1_SMHC_CLK_SRC_SEL (0x3 << 24) 1779 #define D1_SMHC_CLK_SRC_SEL_HOSC (0x0 << 24) 1780 #define D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0 (0x1 << 24) 1781 #define D1_SMHC_FACTOR_N_MASK (0x3 << 8) 1782 #define D1_SMHC_FACTOR_N_SHIFT 8 1783 #define D1_SMHC_FACTOR_M_MASK (0xf << 0) 1784 #define D1_SMHC_FACTOR_M_SHIFT 0 1785 1786 int 1787 sxiccmu_d1_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset, 1788 uint32_t freq) 1789 { 1790 uint32_t parent_freq; 1791 uint32_t reg, m, n; 1792 uint32_t clk_src; 1793 1794 switch (freq) { 1795 case 400000: 1796 n = 2, m = 15; 1797 clk_src = D1_SMHC_CLK_SRC_SEL_HOSC; 1798 break; 1799 case 20000000: 1800 case 25000000: 1801 case 26000000: 1802 case 50000000: 1803 case 52000000: 1804 n = 0, m = 0; 1805 clk_src = D1_SMHC_CLK_SRC_SEL_PLL_PERIPH0; 1806 parent_freq = 1807 sxiccmu_d1_get_frequency(sc, D1_CLK_PLL_PERIPH0); 1808 while ((parent_freq / (1 << n) / 16) > freq) 1809 n++; 1810 while ((parent_freq / (1 << n) / (m + 1)) > freq) 1811 m++; 1812 break; 1813 default: 1814 return -1; 1815 } 1816 1817 reg = SXIREAD4(sc, offset); 1818 reg &= ~D1_SMHC_CLK_SRC_SEL; 1819 reg |= clk_src; 1820 reg &= ~D1_SMHC_FACTOR_N_MASK; 1821 reg |= n << D1_SMHC_FACTOR_N_SHIFT; 1822 reg &= ~D1_SMHC_FACTOR_M_MASK; 1823 reg |= m << D1_SMHC_FACTOR_M_SHIFT; 1824 SXIWRITE4(sc, offset, reg); 1825 1826 return 0; 1827 } 1828 1829 int 1830 sxiccmu_d1_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1831 { 1832 switch (idx) { 1833 case D1_CLK_MMC0: 1834 return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC0_CLK_REG, freq); 1835 case D1_CLK_MMC1: 1836 return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC1_CLK_REG, freq); 1837 case D1_CLK_MMC2: 1838 return sxiccmu_d1_mmc_set_frequency(sc, D1_SMHC2_CLK_REG, freq); 1839 } 1840 1841 printf("%s: 0x%08x\n", __func__, idx); 1842 return -1; 1843 } 1844 1845 int 1846 sxiccmu_h3_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1847 { 1848 struct sxiccmu_clock clock; 1849 uint32_t parent, parent_freq; 1850 uint32_t reg, lock_time; 1851 int k, n; 1852 int error; 1853 1854 switch (idx) { 1855 case H3_CLK_PLL_CPUX: 1856 k = 1; n = 32; 1857 while (k <= 4 && (24000000 * n * k) < freq) 1858 k++; 1859 while (n >= 1 && (24000000 * n * k) > freq) 1860 n--; 1861 1862 /* Gate the PLL first */ 1863 reg = SXIREAD4(sc, H3_PLL_CPUX_CTRL_REG); 1864 reg &= ~H3_PLL_CPUX_ENABLE; 1865 SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg); 1866 1867 /* Set factors and external divider. */ 1868 reg &= ~H3_PLL_CPUX_OUT_EXT_DIVP_MASK; 1869 reg &= ~H3_PLL_CPUX_FACTOR_N_MASK; 1870 reg &= ~H3_PLL_CPUX_FACTOR_K_MASK; 1871 reg &= ~H3_PLL_CPUX_FACTOR_M_MASK; 1872 reg |= ((n - 1) << H3_PLL_CPUX_FACTOR_N_SHIFT); 1873 reg |= ((k - 1) << H3_PLL_CPUX_FACTOR_K_SHIFT); 1874 SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg); 1875 1876 /* Ungate the PLL */ 1877 reg |= H3_PLL_CPUX_ENABLE; 1878 SXIWRITE4(sc, H3_PLL_CPUX_CTRL_REG, reg); 1879 1880 /* Wait for PLL to lock. (LOCK flag is unreliable) */ 1881 lock_time = SXIREAD4(sc, H3_PLL_STABLE_TIME_REG1); 1882 delay(H3_PLL_STABLE_TIME_REG1_TIME(lock_time)); 1883 1884 return 0; 1885 case H3_CLK_CPUX: 1886 /* Switch to 24 MHz clock. */ 1887 reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG); 1888 reg &= ~H3_CPUX_CLK_SRC_SEL; 1889 reg |= H3_CPUX_CLK_SRC_SEL_OSC24M; 1890 SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg); 1891 /* Must wait at least 8 cycles of the current clock. */ 1892 delay(1); 1893 1894 error = sxiccmu_h3_set_frequency(sc, H3_CLK_PLL_CPUX, freq); 1895 1896 /* Switch back to PLL. */ 1897 reg = SXIREAD4(sc, H3_CPUX_AXI_CFG_REG); 1898 reg &= ~H3_CPUX_CLK_SRC_SEL; 1899 reg |= H3_CPUX_CLK_SRC_SEL_PLL_CPUX; 1900 SXIWRITE4(sc, H3_CPUX_AXI_CFG_REG, reg); 1901 /* Must wait at least 8 cycles of the current clock. */ 1902 delay(1); 1903 return error; 1904 case H3_CLK_MMC0: 1905 case H3_CLK_MMC1: 1906 case H3_CLK_MMC2: 1907 clock.sc_iot = sc->sc_iot; 1908 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1909 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 1910 parent = H3_CLK_PLL_PERIPH0; 1911 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 1912 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 1913 } 1914 1915 printf("%s: 0x%08x\n", __func__, idx); 1916 return -1; 1917 } 1918 1919 #define H6_SMHC0_CLK_REG 0x0830 1920 #define H6_SMHC1_CLK_REG 0x0834 1921 #define H6_SMHC2_CLK_REG 0x0838 1922 #define H6_SMHC_CLK_SRC_SEL (0x3 << 24) 1923 #define H6_SMHC_CLK_SRC_SEL_OSC24M (0x0 << 24) 1924 #define H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X (0x1 << 24) 1925 #define H6_SMHC_FACTOR_N_MASK (0x3 << 8) 1926 #define H6_SMHC_FACTOR_N_SHIFT 8 1927 #define H6_SMHC_FACTOR_M_MASK (0xf << 0) 1928 #define H6_SMHC_FACTOR_M_SHIFT 0 1929 1930 int 1931 sxiccmu_h6_mmc_set_frequency(struct sxiccmu_softc *sc, bus_size_t offset, 1932 uint32_t freq, uint32_t parent_freq) 1933 { 1934 uint32_t reg, m, n; 1935 uint32_t clk_src; 1936 1937 switch (freq) { 1938 case 400000: 1939 n = 2, m = 15; 1940 clk_src = H6_SMHC_CLK_SRC_SEL_OSC24M; 1941 break; 1942 case 20000000: 1943 case 25000000: 1944 case 26000000: 1945 case 50000000: 1946 case 52000000: 1947 n = 0, m = 0; 1948 clk_src = H6_SMHC_CLK_SRC_SEL_PLL_PERIPH0_2X; 1949 while ((parent_freq / (1 << n) / 16) > freq) 1950 n++; 1951 while ((parent_freq / (1 << n) / (m + 1)) > freq) 1952 m++; 1953 break; 1954 default: 1955 return -1; 1956 } 1957 1958 reg = SXIREAD4(sc, offset); 1959 reg &= ~H6_SMHC_CLK_SRC_SEL; 1960 reg |= clk_src; 1961 reg &= ~H6_SMHC_FACTOR_N_MASK; 1962 reg |= n << H6_SMHC_FACTOR_N_SHIFT; 1963 reg &= ~H6_SMHC_FACTOR_M_MASK; 1964 reg |= m << H6_SMHC_FACTOR_M_SHIFT; 1965 SXIWRITE4(sc, offset, reg); 1966 1967 return 0; 1968 } 1969 1970 int 1971 sxiccmu_h6_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1972 { 1973 uint32_t parent_freq; 1974 1975 parent_freq = sxiccmu_h6_get_frequency(sc, H6_CLK_PLL_PERIPH0_2X); 1976 1977 switch (idx) { 1978 case H6_CLK_MMC0: 1979 return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC0_CLK_REG, 1980 freq, parent_freq); 1981 case H6_CLK_MMC1: 1982 return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC1_CLK_REG, 1983 freq, parent_freq); 1984 case H6_CLK_MMC2: 1985 return sxiccmu_h6_mmc_set_frequency(sc, H6_SMHC2_CLK_REG, 1986 freq, parent_freq); 1987 } 1988 1989 printf("%s: 0x%08x\n", __func__, idx); 1990 return -1; 1991 } 1992 1993 #define H616_SMHC0_CLK_REG 0x0830 1994 #define H616_SMHC1_CLK_REG 0x0834 1995 #define H616_SMHC2_CLK_REG 0x0838 1996 1997 int 1998 sxiccmu_h616_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 1999 { 2000 uint32_t parent_freq; 2001 2002 parent_freq = sxiccmu_h616_get_frequency(sc, H616_CLK_PLL_PERIPH0_2X); 2003 2004 switch (idx) { 2005 case H616_CLK_MMC0: 2006 return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC0_CLK_REG, 2007 freq, parent_freq); 2008 case H616_CLK_MMC1: 2009 return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC1_CLK_REG, 2010 freq, parent_freq); 2011 case H616_CLK_MMC2: 2012 return sxiccmu_h6_mmc_set_frequency(sc, H616_SMHC2_CLK_REG, 2013 freq, parent_freq); 2014 } 2015 2016 printf("%s: 0x%08x\n", __func__, idx); 2017 return -1; 2018 } 2019 2020 int 2021 sxiccmu_r40_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 2022 { 2023 struct sxiccmu_clock clock; 2024 uint32_t parent, parent_freq; 2025 2026 switch (idx) { 2027 case R40_CLK_MMC0: 2028 case R40_CLK_MMC1: 2029 case R40_CLK_MMC2: 2030 case R40_CLK_MMC3: 2031 clock.sc_iot = sc->sc_iot; 2032 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 2033 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 2034 parent = R40_CLK_PLL_PERIPH0_2X; 2035 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 2036 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 2037 } 2038 2039 printf("%s: 0x%08x\n", __func__, idx); 2040 return -1; 2041 } 2042 2043 int 2044 sxiccmu_v3s_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 2045 { 2046 struct sxiccmu_clock clock; 2047 uint32_t parent, parent_freq; 2048 2049 switch (idx) { 2050 case V3S_CLK_MMC0: 2051 case V3S_CLK_MMC1: 2052 case V3S_CLK_MMC2: 2053 clock.sc_iot = sc->sc_iot; 2054 bus_space_subregion(sc->sc_iot, sc->sc_ioh, 2055 sc->sc_gates[idx].reg, 4, &clock.sc_ioh); 2056 parent = V3S_CLK_PLL_PERIPH0; 2057 parent_freq = sxiccmu_ccu_get_frequency(sc, &parent); 2058 return sxiccmu_mmc_do_set_frequency(&clock, freq, parent_freq); 2059 } 2060 2061 printf("%s: 0x%08x\n", __func__, idx); 2062 return -1; 2063 } 2064 2065 int 2066 sxiccmu_nop_set_frequency(struct sxiccmu_softc *sc, uint32_t idx, uint32_t freq) 2067 { 2068 printf("%s: 0x%08x\n", __func__, idx); 2069 return -1; 2070 } 2071 2072 void 2073 sxiccmu_ccu_enable(void *cookie, uint32_t *cells, int on) 2074 { 2075 struct sxiccmu_softc *sc = cookie; 2076 uint32_t idx = cells[0]; 2077 int reg, bit; 2078 2079 clock_enable_all(sc->sc_node); 2080 2081 if (idx >= sc->sc_ngates || 2082 (sc->sc_gates[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) { 2083 printf("%s: 0x%08x\n", __func__, cells[0]); 2084 return; 2085 } 2086 2087 /* If the clock can't be gated, simply return. */ 2088 if (sc->sc_gates[idx].reg == 0xffff && sc->sc_gates[idx].bit == 0xff) 2089 return; 2090 2091 reg = sc->sc_gates[idx].reg; 2092 bit = sc->sc_gates[idx].bit; 2093 2094 if (on) 2095 SXISET4(sc, reg, (1U << bit)); 2096 else 2097 SXICLR4(sc, reg, (1U << bit)); 2098 } 2099 2100 void 2101 sxiccmu_ccu_reset(void *cookie, uint32_t *cells, int assert) 2102 { 2103 struct sxiccmu_softc *sc = cookie; 2104 uint32_t idx = cells[0]; 2105 int reg, bit; 2106 2107 reset_deassert_all(sc->sc_node); 2108 2109 if (idx >= sc->sc_nresets || 2110 (sc->sc_resets[idx].reg == 0 && sc->sc_gates[idx].bit == 0)) { 2111 printf("%s: 0x%08x\n", __func__, cells[0]); 2112 return; 2113 } 2114 2115 reg = sc->sc_resets[idx].reg; 2116 bit = sc->sc_resets[idx].bit; 2117 2118 if (assert) 2119 SXICLR4(sc, reg, (1U << bit)); 2120 else 2121 SXISET4(sc, reg, (1U << bit)); 2122 } 2123