sunxi_ccu.h revision 1.15
1/* $NetBSD: sunxi_ccu.h,v 1.15 2017/10/28 13:13:45 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2017 Jared McNeill <jmcneill@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 34struct sunxi_ccu_softc; 35struct sunxi_ccu_clk; 36struct sunxi_ccu_reset; 37 38/* 39 * Resets 40 */ 41 42struct 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 57enum 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}; 67 68struct sunxi_ccu_gate { 69 bus_size_t reg; 70 uint32_t mask; 71 const char *parent; 72}; 73 74int sunxi_ccu_gate_enable(struct sunxi_ccu_softc *, 75 struct sunxi_ccu_clk *, int); 76const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *, 77 struct sunxi_ccu_clk *); 78 79#define SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit) \ 80 [_id] = { \ 81 .type = SUNXI_CCU_GATE, \ 82 .base.name = (_name), \ 83 .base.flags = CLK_SET_RATE_PARENT, \ 84 .u.gate.parent = (_pname), \ 85 .u.gate.reg = (_reg), \ 86 .u.gate.mask = __BIT(_bit), \ 87 .enable = sunxi_ccu_gate_enable, \ 88 .get_parent = sunxi_ccu_gate_get_parent, \ 89 } 90 91struct sunxi_ccu_nkmp_tbl { 92 u_int rate; 93 uint32_t n; 94 uint32_t k; 95 uint32_t m; 96 uint32_t p; 97}; 98 99struct sunxi_ccu_nkmp { 100 bus_size_t reg; 101 const char *parent; 102 uint32_t n; 103 uint32_t k; 104 uint32_t m; 105 uint32_t p; 106 uint32_t lock; 107 uint32_t enable; 108 uint32_t flags; 109 const struct sunxi_ccu_nkmp_tbl *table; 110#define SUNXI_CCU_NKMP_DIVIDE_BY_TWO __BIT(0) 111#define SUNXI_CCU_NKMP_FACTOR_N_EXACT __BIT(1) 112#define SUNXI_CCU_NKMP_SCALE_CLOCK __BIT(2) 113#define SUNXI_CCU_NKMP_FACTOR_P_POW2 __BIT(3) 114#define SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE __BIT(4) 115}; 116 117int sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *, 118 struct sunxi_ccu_clk *, int); 119u_int sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *, 120 struct sunxi_ccu_clk *); 121int sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *, 122 struct sunxi_ccu_clk *, u_int); 123const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *, 124 struct sunxi_ccu_clk *); 125 126#define SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 127 _p, _enable, _lock, _tbl, _flags) \ 128 [_id] = { \ 129 .type = SUNXI_CCU_NKMP, \ 130 .base.name = (_name), \ 131 .u.nkmp.reg = (_reg), \ 132 .u.nkmp.parent = (_parent), \ 133 .u.nkmp.n = (_n), \ 134 .u.nkmp.k = (_k), \ 135 .u.nkmp.m = (_m), \ 136 .u.nkmp.p = (_p), \ 137 .u.nkmp.enable = (_enable), \ 138 .u.nkmp.flags = (_flags), \ 139 .u.nkmp.lock = (_lock), \ 140 .u.nkmp.table = (_tbl), \ 141 .enable = sunxi_ccu_nkmp_enable, \ 142 .get_rate = sunxi_ccu_nkmp_get_rate, \ 143 .set_rate = sunxi_ccu_nkmp_set_rate, \ 144 .get_parent = sunxi_ccu_nkmp_get_parent, \ 145 } 146 147#define SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m, \ 148 _p, _enable, _flags) \ 149 SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \ 150 _p, _enable, 0, NULL, _flags) 151 152 153struct sunxi_ccu_nm { 154 bus_size_t reg; 155 const char **parents; 156 u_int nparents; 157 uint32_t n; 158 uint32_t m; 159 uint32_t sel; 160 uint32_t enable; 161 uint32_t flags; 162#define SUNXI_CCU_NM_POWER_OF_TWO __BIT(0) 163#define SUNXI_CCU_NM_ROUND_DOWN __BIT(1) 164#define SUNXI_CCU_NM_DIVIDE_BY_TWO __BIT(2) 165}; 166 167int sunxi_ccu_nm_enable(struct sunxi_ccu_softc *, 168 struct sunxi_ccu_clk *, int); 169u_int sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *, 170 struct sunxi_ccu_clk *); 171int sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *, 172 struct sunxi_ccu_clk *, u_int); 173int sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *, 174 struct sunxi_ccu_clk *, 175 const char *); 176const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *, 177 struct sunxi_ccu_clk *); 178 179#define SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel, \ 180 _enable, _flags) \ 181 [_id] = { \ 182 .type = SUNXI_CCU_NM, \ 183 .base.name = (_name), \ 184 .u.nm.reg = (_reg), \ 185 .u.nm.parents = (_parents), \ 186 .u.nm.nparents = __arraycount(_parents), \ 187 .u.nm.n = (_n), \ 188 .u.nm.m = (_m), \ 189 .u.nm.sel = (_sel), \ 190 .u.nm.enable = (_enable), \ 191 .u.nm.flags = (_flags), \ 192 .enable = sunxi_ccu_nm_enable, \ 193 .get_rate = sunxi_ccu_nm_get_rate, \ 194 .set_rate = sunxi_ccu_nm_set_rate, \ 195 .set_parent = sunxi_ccu_nm_set_parent, \ 196 .get_parent = sunxi_ccu_nm_get_parent, \ 197 } 198 199struct sunxi_ccu_div { 200 bus_size_t reg; 201 const char **parents; 202 u_int nparents; 203 uint32_t div; 204 uint32_t sel; 205 uint32_t enable; 206 uint32_t flags; 207#define SUNXI_CCU_DIV_POWER_OF_TWO __BIT(0) 208#define SUNXI_CCU_DIV_ZERO_IS_ONE __BIT(1) 209#define SUNXI_CCU_DIV_TIMES_TWO __BIT(2) 210#define SUNXI_CCU_DIV_SET_RATE_PARENT __BIT(3) 211}; 212 213int sunxi_ccu_div_enable(struct sunxi_ccu_softc *, 214 struct sunxi_ccu_clk *, int); 215u_int sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *, 216 struct sunxi_ccu_clk *); 217int sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *, 218 struct sunxi_ccu_clk *, u_int); 219int sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *, 220 struct sunxi_ccu_clk *, 221 const char *); 222const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *, 223 struct sunxi_ccu_clk *); 224 225#define SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div, \ 226 _sel, _flags) \ 227 SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \ 228 _sel, 0, _flags) 229 230#define SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \ 231 _sel, _enable, _flags) \ 232 [_id] = { \ 233 .type = SUNXI_CCU_DIV, \ 234 .base.name = (_name), \ 235 .u.div.reg = (_reg), \ 236 .u.div.parents = (_parents), \ 237 .u.div.nparents = __arraycount(_parents), \ 238 .u.div.div = (_div), \ 239 .u.div.sel = (_sel), \ 240 .u.div.enable = (_enable), \ 241 .u.div.flags = (_flags), \ 242 .enable = sunxi_ccu_div_enable, \ 243 .get_rate = sunxi_ccu_div_get_rate, \ 244 .set_rate = sunxi_ccu_div_set_rate, \ 245 .set_parent = sunxi_ccu_div_set_parent, \ 246 .get_parent = sunxi_ccu_div_get_parent, \ 247 } 248 249struct sunxi_ccu_prediv { 250 bus_size_t reg; 251 const char **parents; 252 u_int nparents; 253 uint32_t prediv; 254 uint32_t prediv_sel; 255 uint32_t prediv_fixed; 256 uint32_t div; 257 uint32_t sel; 258 uint32_t flags; 259#define SUNXI_CCU_PREDIV_POWER_OF_TWO __BIT(0) 260#define SUNXI_CCU_PREDIV_DIVIDE_BY_TWO __BIT(1) 261}; 262 263u_int sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *, 264 struct sunxi_ccu_clk *); 265int sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *, 266 struct sunxi_ccu_clk *, u_int); 267int sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *, 268 struct sunxi_ccu_clk *, 269 const char *); 270const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *, 271 struct sunxi_ccu_clk *); 272 273#define SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv, \ 274 _prediv_sel, _div, _sel, _flags) \ 275 SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \ 276 _prediv_sel, 0, _div, _sel, _flags) 277 278#define SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \ 279 _prediv_sel, _prediv_fixed, _div, _sel, _flags) \ 280 [_id] = { \ 281 .type = SUNXI_CCU_PREDIV, \ 282 .base.name = (_name), \ 283 .u.prediv.reg = (_reg), \ 284 .u.prediv.parents = (_parents), \ 285 .u.prediv.nparents = __arraycount(_parents), \ 286 .u.prediv.prediv = (_prediv), \ 287 .u.prediv.prediv_sel = (_prediv_sel), \ 288 .u.prediv.prediv_fixed = (_prediv_fixed), \ 289 .u.prediv.div = (_div), \ 290 .u.prediv.sel = (_sel), \ 291 .u.prediv.flags = (_flags), \ 292 .get_rate = sunxi_ccu_prediv_get_rate, \ 293 .set_rate = sunxi_ccu_prediv_set_rate, \ 294 .set_parent = sunxi_ccu_prediv_set_parent, \ 295 .get_parent = sunxi_ccu_prediv_get_parent, \ 296 } 297 298struct sunxi_ccu_phase { 299 bus_size_t reg; 300 const char *parent; 301 uint32_t mask; 302}; 303 304u_int sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *, 305 struct sunxi_ccu_clk *); 306int sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *, 307 struct sunxi_ccu_clk *, u_int); 308const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *, 309 struct sunxi_ccu_clk *); 310 311#define SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask) \ 312 [_id] = { \ 313 .type = SUNXI_CCU_PHASE, \ 314 .base.name = (_name), \ 315 .u.phase.reg = (_reg), \ 316 .u.phase.parent = (_parent), \ 317 .u.phase.mask = (_mask), \ 318 .get_rate = sunxi_ccu_phase_get_rate, \ 319 .set_rate = sunxi_ccu_phase_set_rate, \ 320 .get_parent = sunxi_ccu_phase_get_parent, \ 321 } 322 323struct sunxi_ccu_fixed_factor { 324 const char *parent; 325 u_int div; 326 u_int mult; 327}; 328 329u_int sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *, 330 struct sunxi_ccu_clk *); 331const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *, 332 struct sunxi_ccu_clk *); 333 334#define SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult) \ 335 [_id] = { \ 336 .type = SUNXI_CCU_FIXED_FACTOR, \ 337 .base.name = (_name), \ 338 .u.fixed_factor.parent = (_parent), \ 339 .u.fixed_factor.div = (_div), \ 340 .u.fixed_factor.mult = (_mult), \ 341 .get_rate = sunxi_ccu_fixed_factor_get_rate, \ 342 .get_parent = sunxi_ccu_fixed_factor_get_parent, \ 343 } 344 345struct sunxi_ccu_clk { 346 struct clk base; 347 enum sunxi_ccu_clktype type; 348 union { 349 struct sunxi_ccu_gate gate; 350 struct sunxi_ccu_nm nm; 351 struct sunxi_ccu_nkmp nkmp; 352 struct sunxi_ccu_prediv prediv; 353 struct sunxi_ccu_div div; 354 struct sunxi_ccu_phase phase; 355 struct sunxi_ccu_fixed_factor fixed_factor; 356 } u; 357 358 int (*enable)(struct sunxi_ccu_softc *, 359 struct sunxi_ccu_clk *, int); 360 u_int (*get_rate)(struct sunxi_ccu_softc *, 361 struct sunxi_ccu_clk *); 362 int (*set_rate)(struct sunxi_ccu_softc *, 363 struct sunxi_ccu_clk *, u_int); 364 const char * (*get_parent)(struct sunxi_ccu_softc *, 365 struct sunxi_ccu_clk *); 366 int (*set_parent)(struct sunxi_ccu_softc *, 367 struct sunxi_ccu_clk *, 368 const char *); 369}; 370 371struct sunxi_ccu_softc { 372 device_t sc_dev; 373 int sc_phandle; 374 bus_space_tag_t sc_bst; 375 bus_space_handle_t sc_bsh; 376 377 struct clk_domain sc_clkdom; 378 379 struct sunxi_ccu_reset *sc_resets; 380 u_int sc_nresets; 381 382 struct sunxi_ccu_clk *sc_clks; 383 u_int sc_nclks; 384}; 385 386int sunxi_ccu_attach(struct sunxi_ccu_softc *); 387struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *, 388 const char *); 389void sunxi_ccu_print(struct sunxi_ccu_softc *); 390 391#define CCU_READ(sc, reg) \ 392 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 393#define CCU_WRITE(sc, reg, val) \ 394 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 395 396#endif /* _ARM_SUNXI_CCU_H */ 397