1 /* $NetBSD: sunxi_ccu.h,v 1.25 2026/10/04 03:03:17 rxg Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 Jared McNeill <jmcneill (at) invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #ifndef _ARM_SUNXI_CCU_H 30 #define _ARM_SUNXI_CCU_H 31 32 #include <dev/clk/clk_backend.h> 33 34 struct sunxi_ccu_softc; 35 struct sunxi_ccu_clk; 36 struct sunxi_ccu_reset; 37 38 /* 39 * Resets 40 */ 41 42 struct sunxi_ccu_reset { 43 bus_size_t reg; 44 uint32_t mask; 45 }; 46 47 #define SUNXI_CCU_RESET(_id, _reg, _bit) \ 48 [_id] = { \ 49 .reg = (_reg), \ 50 .mask = __BIT(_bit), \ 51 } 52 53 /* 54 * Clocks 55 */ 56 57 enum sunxi_ccu_clktype { 58 SUNXI_CCU_UNKNOWN, 59 SUNXI_CCU_GATE, 60 SUNXI_CCU_NM, 61 SUNXI_CCU_NKMP, 62 SUNXI_CCU_PREDIV, 63 SUNXI_CCU_DIV, 64 SUNXI_CCU_PHASE, 65 SUNXI_CCU_FIXED_FACTOR, 66 SUNXI_CCU_FRACTIONAL, 67 SUNXI_CCU_MUX, 68 }; 69 70 struct sunxi_ccu_gate { 71 bus_size_t reg; 72 uint32_t mask; 73 const char *parent; 74 }; 75 76 int sunxi_ccu_gate_enable(struct sunxi_ccu_softc *, 77 struct sunxi_ccu_clk *, int); 78 const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *, 79 struct sunxi_ccu_clk *); 80 81 #define SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit) \ 82 [_id] = { \ 83 .type = SUNXI_CCU_GATE, \ 84 .base.name = (_name), \ 85 .base.flags = CLK_SET_RATE_PARENT, \ 86 .u.gate.parent = (_pname), \ 87 .u.gate.reg = (_reg), \ 88 .u.gate.mask = __BIT(_bit), \ 89 .enable = sunxi_ccu_gate_enable, \ 90 .get_parent = sunxi_ccu_gate_get_parent, \ 91 } 92 93 struct sunxi_ccu_nkmp_tbl { 94 u_int rate; 95 uint32_t n; 96 uint32_t k; 97 uint32_t m; 98 uint32_t p; 99 uint32_t pat; 100 }; 101 102 struct sunxi_ccu_nkmp_pat { 103 bus_size_t reg; 104 }; 105 106 struct sunxi_ccu_nkmp { 107 bus_size_t reg; 108 const char *parent; 109 uint32_t n; 110 uint32_t k; 111 uint32_t m; 112 uint32_t p; 113 uint32_t lock; 114 uint32_t sdm_en; 115 uint32_t enable; 116 uint32_t flags; 117 const struct sunxi_ccu_nkmp_pat *pat; 118 const struct sunxi_ccu_nkmp_tbl *table; 119 #define SUNXI_CCU_NKMP_DIVIDE_BY_TWO __BIT(0) 120 #define SUNXI_CCU_NKMP_FACTOR_N_EXACT __BIT(1) 121 #define SUNXI_CCU_NKMP_SCALE_CLOCK __BIT(2) 122 #define SUNXI_CCU_NKMP_FACTOR_P_POW2 __BIT(3) 123 #define SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE __BIT(4) 124 #define SUNXI_CCU_NKMP_FACTOR_P_X4 __BIT(5) 125 }; 126 127 int sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *, 128 struct sunxi_ccu_clk *, int); 129 u_int sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *, 130 struct sunxi_ccu_clk *); 131 int sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *, 132 struct sunxi_ccu_clk *, u_int); 133 const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *, 134 struct sunxi_ccu_clk *); 135 136 #define SUNXI_CCU_NKMP_SDM_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 137 _p, _enable, _lock, _sdm_en, _pat, _tbl, \ 138 _flags) \ 139 [_id] = { \ 140 .type = SUNXI_CCU_NKMP, \ 141 .base.name = (_name), \ 142 .u.nkmp.reg = (_reg), \ 143 .u.nkmp.parent = (_parent), \ 144 .u.nkmp.n = (_n), \ 145 .u.nkmp.k = (_k), \ 146 .u.nkmp.m = (_m), \ 147 .u.nkmp.p = (_p), \ 148 .u.nkmp.enable = (_enable), \ 149 .u.nkmp.flags = (_flags), \ 150 .u.nkmp.lock = (_lock), \ 151 .u.nkmp.sdm_en = (_sdm_en), \ 152 .u.nkmp.pat = (_pat), \ 153 .u.nkmp.table = (_tbl), \ 154 .enable = sunxi_ccu_nkmp_enable, \ 155 .get_rate = sunxi_ccu_nkmp_get_rate, \ 156 .set_rate = sunxi_ccu_nkmp_set_rate, \ 157 .get_parent = sunxi_ccu_nkmp_get_parent, \ 158 } 159 160 #define SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 161 _p, _enable, _lock, _tbl, _flags) \ 162 SUNXI_CCU_NKMP_SDM_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 163 _p, _enable, _lock, 0, NULL, _tbl, _flags) 164 #define SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m, \ 165 _p, _enable, _flags) \ 166 SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 167 _p, _enable, 0, NULL, _flags) 168 169 170 struct sunxi_ccu_nm { 171 bus_size_t reg; 172 const char **parents; 173 u_int nparents; 174 uint32_t n; 175 uint32_t m; 176 uint32_t sel; 177 uint32_t enable; 178 uint32_t flags; 179 #define SUNXI_CCU_NM_POWER_OF_TWO __BIT(0) 180 #define SUNXI_CCU_NM_ROUND_DOWN __BIT(1) 181 #define SUNXI_CCU_NM_DIVIDE_BY_TWO __BIT(2) 182 }; 183 184 int sunxi_ccu_nm_enable(struct sunxi_ccu_softc *, 185 struct sunxi_ccu_clk *, int); 186 u_int sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *, 187 struct sunxi_ccu_clk *); 188 int sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *, 189 struct sunxi_ccu_clk *, u_int); 190 int sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *, 191 struct sunxi_ccu_clk *, 192 const char *); 193 const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *, 194 struct sunxi_ccu_clk *); 195 196 #define SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel, \ 197 _enable, _flags) \ 198 [_id] = { \ 199 .type = SUNXI_CCU_NM, \ 200 .base.name = (_name), \ 201 .u.nm.reg = (_reg), \ 202 .u.nm.parents = (_parents), \ 203 .u.nm.nparents = __arraycount(_parents), \ 204 .u.nm.n = (_n), \ 205 .u.nm.m = (_m), \ 206 .u.nm.sel = (_sel), \ 207 .u.nm.enable = (_enable), \ 208 .u.nm.flags = (_flags), \ 209 .enable = sunxi_ccu_nm_enable, \ 210 .get_rate = sunxi_ccu_nm_get_rate, \ 211 .set_rate = sunxi_ccu_nm_set_rate, \ 212 .set_parent = sunxi_ccu_nm_set_parent, \ 213 .get_parent = sunxi_ccu_nm_get_parent, \ 214 } 215 216 struct sunxi_ccu_div { 217 bus_size_t reg; 218 const char **parents; 219 u_int nparents; 220 uint32_t div; 221 uint32_t sel; 222 uint32_t enable; 223 uint32_t flags; 224 #define SUNXI_CCU_DIV_POWER_OF_TWO __BIT(0) 225 #define SUNXI_CCU_DIV_ZERO_IS_ONE __BIT(1) 226 #define SUNXI_CCU_DIV_TIMES_TWO __BIT(2) 227 #define SUNXI_CCU_DIV_SET_RATE_PARENT __BIT(3) 228 }; 229 230 int sunxi_ccu_div_enable(struct sunxi_ccu_softc *, 231 struct sunxi_ccu_clk *, int); 232 u_int sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *, 233 struct sunxi_ccu_clk *); 234 int sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *, 235 struct sunxi_ccu_clk *, u_int); 236 int sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *, 237 struct sunxi_ccu_clk *, 238 const char *); 239 const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *, 240 struct sunxi_ccu_clk *); 241 242 #define SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div, \ 243 _sel, _flags) \ 244 SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \ 245 _sel, 0, _flags) 246 247 #define SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \ 248 _sel, _enable, _flags) \ 249 [_id] = { \ 250 .type = SUNXI_CCU_DIV, \ 251 .base.name = (_name), \ 252 .u.div.reg = (_reg), \ 253 .u.div.parents = (_parents), \ 254 .u.div.nparents = __arraycount(_parents), \ 255 .u.div.div = (_div), \ 256 .u.div.sel = (_sel), \ 257 .u.div.enable = (_enable), \ 258 .u.div.flags = (_flags), \ 259 .enable = sunxi_ccu_div_enable, \ 260 .get_rate = sunxi_ccu_div_get_rate, \ 261 .set_rate = sunxi_ccu_div_set_rate, \ 262 .set_parent = sunxi_ccu_div_set_parent, \ 263 .get_parent = sunxi_ccu_div_get_parent, \ 264 } 265 266 /* special case of the div model for display clocks */ 267 int sunxi_ccu_lcdxch0_set_rate(struct sunxi_ccu_softc *, 268 struct sunxi_ccu_clk *, struct sunxi_ccu_clk *, 269 struct sunxi_ccu_clk *, u_int); 270 u_int sunxi_ccu_lcdxch0_round_rate(struct sunxi_ccu_softc *, 271 struct sunxi_ccu_clk *, struct sunxi_ccu_clk *, 272 struct sunxi_ccu_clk *, u_int); 273 274 int sunxi_ccu_lcdxch1_set_rate(struct sunxi_ccu_softc *sc, 275 struct sunxi_ccu_clk *clk, struct sunxi_ccu_clk *pclk, 276 struct sunxi_ccu_clk *pclk_x2, u_int); 277 278 struct sunxi_ccu_prediv { 279 bus_size_t reg; 280 const char **parents; 281 u_int nparents; 282 uint32_t prediv; 283 uint32_t prediv_sel; 284 uint32_t prediv_fixed; 285 uint32_t div; 286 uint32_t sel; 287 uint32_t flags; 288 #define SUNXI_CCU_PREDIV_POWER_OF_TWO __BIT(0) 289 #define SUNXI_CCU_PREDIV_DIVIDE_BY_TWO __BIT(1) 290 }; 291 292 u_int sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *, 293 struct sunxi_ccu_clk *); 294 int sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *, 295 struct sunxi_ccu_clk *, u_int); 296 int sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *, 297 struct sunxi_ccu_clk *, 298 const char *); 299 const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *, 300 struct sunxi_ccu_clk *); 301 302 #define SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv, \ 303 _prediv_sel, _div, _sel, _flags) \ 304 SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \ 305 _prediv_sel, 0, _div, _sel, _flags) 306 307 #define SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \ 308 _prediv_sel, _prediv_fixed, _div, _sel, _flags) \ 309 [_id] = { \ 310 .type = SUNXI_CCU_PREDIV, \ 311 .base.name = (_name), \ 312 .u.prediv.reg = (_reg), \ 313 .u.prediv.parents = (_parents), \ 314 .u.prediv.nparents = __arraycount(_parents), \ 315 .u.prediv.prediv = (_prediv), \ 316 .u.prediv.prediv_sel = (_prediv_sel), \ 317 .u.prediv.prediv_fixed = (_prediv_fixed), \ 318 .u.prediv.div = (_div), \ 319 .u.prediv.sel = (_sel), \ 320 .u.prediv.flags = (_flags), \ 321 .get_rate = sunxi_ccu_prediv_get_rate, \ 322 .set_rate = sunxi_ccu_prediv_set_rate, \ 323 .set_parent = sunxi_ccu_prediv_set_parent, \ 324 .get_parent = sunxi_ccu_prediv_get_parent, \ 325 } 326 327 struct sunxi_ccu_phase { 328 bus_size_t reg; 329 const char *parent; 330 uint32_t mask; 331 }; 332 333 u_int sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *, 334 struct sunxi_ccu_clk *); 335 int sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *, 336 struct sunxi_ccu_clk *, u_int); 337 const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *, 338 struct sunxi_ccu_clk *); 339 340 #define SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask) \ 341 [_id] = { \ 342 .type = SUNXI_CCU_PHASE, \ 343 .base.name = (_name), \ 344 .u.phase.reg = (_reg), \ 345 .u.phase.parent = (_parent), \ 346 .u.phase.mask = (_mask), \ 347 .get_rate = sunxi_ccu_phase_get_rate, \ 348 .set_rate = sunxi_ccu_phase_set_rate, \ 349 .get_parent = sunxi_ccu_phase_get_parent, \ 350 } 351 352 struct sunxi_ccu_fixed_factor { 353 const char *parent; 354 u_int div; 355 u_int mult; 356 }; 357 358 u_int sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *, 359 struct sunxi_ccu_clk *); 360 int sunxi_ccu_fixed_factor_set_rate(struct sunxi_ccu_softc *, 361 struct sunxi_ccu_clk *, u_int); 362 const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *, 363 struct sunxi_ccu_clk *); 364 365 #define SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult) \ 366 [_id] = { \ 367 .type = SUNXI_CCU_FIXED_FACTOR, \ 368 .base.name = (_name), \ 369 .u.fixed_factor.parent = (_parent), \ 370 .u.fixed_factor.div = (_div), \ 371 .u.fixed_factor.mult = (_mult), \ 372 .get_rate = sunxi_ccu_fixed_factor_get_rate, \ 373 .get_parent = sunxi_ccu_fixed_factor_get_parent, \ 374 .set_rate = sunxi_ccu_fixed_factor_set_rate, \ 375 } 376 377 struct sunxi_ccu_fractional { 378 bus_size_t reg; 379 const char *parent; 380 uint32_t m; 381 uint32_t m_min; 382 uint32_t m_max; 383 uint32_t div_en; 384 uint32_t frac_sel; 385 uint32_t frac[2]; 386 uint32_t prediv; 387 uint32_t prediv_val; 388 uint32_t enable; 389 uint32_t flags; 390 #define SUNXI_CCU_FRACTIONAL_PLUSONE __BIT(0) 391 #define SUNXI_CCU_FRACTIONAL_SET_ENABLE __BIT(1) 392 }; 393 394 int sunxi_ccu_fractional_enable(struct sunxi_ccu_softc *, 395 struct sunxi_ccu_clk *, int); 396 u_int sunxi_ccu_fractional_get_rate(struct sunxi_ccu_softc *, 397 struct sunxi_ccu_clk *); 398 int sunxi_ccu_fractional_set_rate(struct sunxi_ccu_softc *, 399 struct sunxi_ccu_clk *, u_int); 400 u_int sunxi_ccu_fractional_round_rate(struct sunxi_ccu_softc *, 401 struct sunxi_ccu_clk *, u_int); 402 const char *sunxi_ccu_fractional_get_parent(struct sunxi_ccu_softc *, 403 struct sunxi_ccu_clk *); 404 405 #define SUNXI_CCU_FRACTIONAL(_id, _name, _parent, _reg, _m, _m_min, _m_max, \ 406 _div_en, _frac_sel, _frac0, _frac1, _prediv, _prediv_val, \ 407 _enable, _flags) \ 408 [_id] = { \ 409 .type = SUNXI_CCU_FRACTIONAL, \ 410 .base.name = (_name), \ 411 .u.fractional.reg = (_reg), \ 412 .u.fractional.parent = (_parent), \ 413 .u.fractional.m = (_m), \ 414 .u.fractional.m_min = (_m_min), \ 415 .u.fractional.m_max = (_m_max), \ 416 .u.fractional.prediv = (_prediv), \ 417 .u.fractional.prediv_val = (_prediv_val), \ 418 .u.fractional.div_en = (_div_en), \ 419 .u.fractional.frac_sel = (_frac_sel), \ 420 .u.fractional.frac[0] = (_frac0), \ 421 .u.fractional.frac[1] = (_frac1), \ 422 .u.fractional.enable = (_enable), \ 423 .u.fractional.flags = (_flags), \ 424 .enable = sunxi_ccu_fractional_enable, \ 425 .get_rate = sunxi_ccu_fractional_get_rate, \ 426 .set_rate = sunxi_ccu_fractional_set_rate, \ 427 .round_rate = sunxi_ccu_fractional_round_rate, \ 428 .get_parent = sunxi_ccu_fractional_get_parent, \ 429 } 430 431 struct sunxi_ccu_mux { 432 bus_size_t reg; 433 const char **parents; 434 u_int nparents; 435 uint32_t sel; 436 uint32_t flags; 437 }; 438 439 int sunxi_ccu_mux_set_parent(struct sunxi_ccu_softc *, 440 struct sunxi_ccu_clk *, 441 const char *); 442 const char *sunxi_ccu_mux_get_parent(struct sunxi_ccu_softc *, 443 struct sunxi_ccu_clk *); 444 445 #define SUNXI_CCU_MUX(_id, _name, _parents, _reg, _sel, _flags) \ 446 [_id] = { \ 447 .type = SUNXI_CCU_MUX, \ 448 .base.name = (_name), \ 449 .base.flags = CLK_SET_RATE_PARENT, \ 450 .u.mux.reg = (_reg), \ 451 .u.mux.parents = (_parents), \ 452 .u.mux.nparents = __arraycount(_parents), \ 453 .u.mux.sel = (_sel), \ 454 .u.mux.flags = (_flags), \ 455 .set_parent = sunxi_ccu_mux_set_parent, \ 456 .get_parent = sunxi_ccu_mux_get_parent, \ 457 } 458 459 460 struct sunxi_ccu_clk { 461 struct clk base; 462 enum sunxi_ccu_clktype type; 463 union { 464 struct sunxi_ccu_gate gate; 465 struct sunxi_ccu_nm nm; 466 struct sunxi_ccu_nkmp nkmp; 467 struct sunxi_ccu_prediv prediv; 468 struct sunxi_ccu_div div; 469 struct sunxi_ccu_phase phase; 470 struct sunxi_ccu_fixed_factor fixed_factor; 471 struct sunxi_ccu_fractional fractional; 472 struct sunxi_ccu_mux mux; 473 } u; 474 475 int (*enable)(struct sunxi_ccu_softc *, 476 struct sunxi_ccu_clk *, int); 477 u_int (*get_rate)(struct sunxi_ccu_softc *, 478 struct sunxi_ccu_clk *); 479 int (*set_rate)(struct sunxi_ccu_softc *, 480 struct sunxi_ccu_clk *, u_int); 481 u_int (*round_rate)(struct sunxi_ccu_softc *, 482 struct sunxi_ccu_clk *, u_int); 483 const char * (*get_parent)(struct sunxi_ccu_softc *, 484 struct sunxi_ccu_clk *); 485 int (*set_parent)(struct sunxi_ccu_softc *, 486 struct sunxi_ccu_clk *, 487 const char *); 488 }; 489 490 struct sunxi_ccu_softc { 491 device_t sc_dev; 492 int sc_phandle; 493 bus_space_tag_t sc_bst; 494 bus_space_handle_t sc_bsh; 495 496 struct clk_domain sc_clkdom; 497 498 struct sunxi_ccu_reset *sc_resets; 499 u_int sc_nresets; 500 501 struct sunxi_ccu_clk *sc_clks; 502 u_int sc_nclks; 503 }; 504 505 int sunxi_ccu_attach(struct sunxi_ccu_softc *); 506 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *, 507 const char *); 508 void sunxi_ccu_print(struct sunxi_ccu_softc *); 509 510 #define CCU_READ(sc, reg) \ 511 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 512 #define CCU_WRITE(sc, reg, val) \ 513 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 514 515 #endif /* _ARM_SUNXI_CCU_H */ 516