1 /* $NetBSD: meson_clk.h,v 1.3 2019/02/25 19:30:17 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2017-2019 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_MESON_CLK_H 30 #define _ARM_MESON_CLK_H 31 32 #include <dev/clk/clk_backend.h> 33 #include <dev/fdt/syscon.h> 34 35 struct meson_clk_softc; 36 struct meson_clk_clk; 37 struct meson_clk_reset; 38 39 /* 40 * Resets 41 */ 42 43 struct meson_clk_reset { 44 bus_size_t reg; 45 uint32_t mask; 46 }; 47 48 #define MESON_CLK_RESET(_id, _reg, _bit) \ 49 [_id] = { \ 50 .reg = (_reg), \ 51 .mask = __BIT(_bit), \ 52 } 53 54 /* 55 * Clocks 56 */ 57 58 enum meson_clk_clktype { 59 MESON_CLK_UNKNOWN, 60 MESON_CLK_FIXED, 61 MESON_CLK_GATE, 62 MESON_CLK_PLL, 63 MESON_CLK_MPLL, 64 MESON_CLK_DIV, 65 MESON_CLK_FIXED_FACTOR, 66 MESON_CLK_MUX, 67 }; 68 69 /* 70 * Fixed clocks 71 */ 72 73 struct meson_clk_fixed { 74 u_int rate; 75 }; 76 77 u_int meson_clk_fixed_get_rate(struct meson_clk_softc *, struct meson_clk_clk *); 78 79 #define MESON_CLK_FIXED(_id, _name, _rate) \ 80 [_id] = { \ 81 .type = MESON_CLK_FIXED, \ 82 .base.name = (_name), \ 83 .base.flags = 0, \ 84 .u.fixed.rate = (_rate), \ 85 .get_rate = meson_clk_fixed_get_rate, \ 86 } 87 88 /* 89 * Gate clocks 90 */ 91 92 struct meson_clk_gate { 93 bus_size_t reg; 94 uint32_t mask; 95 const char *parent; 96 uint32_t flags; 97 #define MESON_CLK_GATE_SET_TO_DISABLE __BIT(0) 98 }; 99 100 int meson_clk_gate_enable(struct meson_clk_softc *, 101 struct meson_clk_clk *, int); 102 const char *meson_clk_gate_get_parent(struct meson_clk_softc *, 103 struct meson_clk_clk *); 104 105 #define MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, _flags) \ 106 [_id] = { \ 107 .type = MESON_CLK_GATE, \ 108 .base.name = (_name), \ 109 .base.flags = CLK_SET_RATE_PARENT, \ 110 .u.gate.parent = (_pname), \ 111 .u.gate.reg = (_reg), \ 112 .u.gate.mask = __BIT(_bit), \ 113 .u.gate.flags = (_flags), \ 114 .enable = meson_clk_gate_enable, \ 115 .get_parent = meson_clk_gate_get_parent, \ 116 } 117 118 #define MESON_CLK_GATE(_id, _name, _pname, _reg, _bit) \ 119 MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, 0) 120 121 /* 122 * Divider clocks 123 */ 124 125 struct meson_clk_div { 126 bus_size_t reg; 127 const char *parent; 128 uint32_t div; 129 uint32_t flags; 130 #define MESON_CLK_DIV_POWER_OF_TWO __BIT(0) 131 #define MESON_CLK_DIV_SET_RATE_PARENT __BIT(1) 132 #define MESON_CLK_DIV_CPU_SCALE_TABLE __BIT(2) 133 }; 134 135 u_int meson_clk_div_get_rate(struct meson_clk_softc *, 136 struct meson_clk_clk *); 137 int meson_clk_div_set_rate(struct meson_clk_softc *, 138 struct meson_clk_clk *, u_int); 139 const char *meson_clk_div_get_parent(struct meson_clk_softc *, 140 struct meson_clk_clk *); 141 142 #define MESON_CLK_DIV(_id, _name, _parent, _reg, _div, _flags) \ 143 [_id] = { \ 144 .type = MESON_CLK_DIV, \ 145 .base.name = (_name), \ 146 .u.div.reg = (_reg), \ 147 .u.div.parent = (_parent), \ 148 .u.div.div = (_div), \ 149 .u.div.flags = (_flags), \ 150 .get_rate = meson_clk_div_get_rate, \ 151 .set_rate = meson_clk_div_set_rate, \ 152 .get_parent = meson_clk_div_get_parent, \ 153 } 154 155 /* 156 * Fixed-factor clocks 157 */ 158 159 struct meson_clk_fixed_factor { 160 const char *parent; 161 u_int div; 162 u_int mult; 163 }; 164 165 u_int meson_clk_fixed_factor_get_rate(struct meson_clk_softc *, 166 struct meson_clk_clk *); 167 int meson_clk_fixed_factor_set_rate(struct meson_clk_softc *, 168 struct meson_clk_clk *, u_int); 169 const char *meson_clk_fixed_factor_get_parent(struct meson_clk_softc *, 170 struct meson_clk_clk *); 171 172 #define MESON_CLK_FIXED_FACTOR(_id, _name, _parent, _div, _mult) \ 173 [_id] = { \ 174 .type = MESON_CLK_FIXED_FACTOR, \ 175 .base.name = (_name), \ 176 .u.fixed_factor.parent = (_parent), \ 177 .u.fixed_factor.div = (_div), \ 178 .u.fixed_factor.mult = (_mult), \ 179 .get_rate = meson_clk_fixed_factor_get_rate, \ 180 .get_parent = meson_clk_fixed_factor_get_parent, \ 181 .set_rate = meson_clk_fixed_factor_set_rate, \ 182 } 183 184 /* 185 * Mux clocks 186 */ 187 188 struct meson_clk_mux { 189 bus_size_t reg; 190 const char **parents; 191 u_int nparents; 192 uint32_t sel; 193 uint32_t flags; 194 }; 195 196 const char *meson_clk_mux_get_parent(struct meson_clk_softc *, 197 struct meson_clk_clk *); 198 199 #define MESON_CLK_MUX(_id, _name, _parents, _reg, _sel, _flags) \ 200 [_id] = { \ 201 .type = MESON_CLK_MUX, \ 202 .base.name = (_name), \ 203 .base.flags = CLK_SET_RATE_PARENT, \ 204 .u.mux.parents = (_parents), \ 205 .u.mux.nparents = __arraycount(_parents), \ 206 .u.mux.reg = (_reg), \ 207 .u.mux.sel = (_sel), \ 208 .u.mux.flags = (_flags), \ 209 .get_parent = meson_clk_mux_get_parent, \ 210 } 211 212 /* 213 * PLL clocks 214 */ 215 216 struct meson_clk_pll_reg { 217 bus_size_t reg; 218 uint32_t mask; 219 }; 220 221 #define MESON_CLK_PLL_REG(_reg, _mask) \ 222 { .reg = (_reg), .mask = (_mask) } 223 #define MESON_CLK_PLL_REG_INVALID MESON_CLK_PLL_REG(0,0) 224 225 struct meson_clk_pll { 226 struct meson_clk_pll_reg enable; 227 struct meson_clk_pll_reg m; 228 struct meson_clk_pll_reg n; 229 struct meson_clk_pll_reg frac; 230 struct meson_clk_pll_reg l; 231 struct meson_clk_pll_reg reset; 232 const char *parent; 233 uint32_t flags; 234 }; 235 236 u_int meson_clk_pll_get_rate(struct meson_clk_softc *, 237 struct meson_clk_clk *); 238 const char *meson_clk_pll_get_parent(struct meson_clk_softc *, 239 struct meson_clk_clk *); 240 241 #define MESON_CLK_PLL_RATE(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 242 _reset, _setratefn, _flags) \ 243 [_id] = { \ 244 .type = MESON_CLK_PLL, \ 245 .base.name = (_name), \ 246 .u.pll.parent = (_parent), \ 247 .u.pll.enable = _enable, \ 248 .u.pll.m = _m, \ 249 .u.pll.n = _n, \ 250 .u.pll.frac = _frac, \ 251 .u.pll.l = _l, \ 252 .u.pll.reset = _reset, \ 253 .u.pll.flags = (_flags), \ 254 .set_rate = (_setratefn), \ 255 .get_rate = meson_clk_pll_get_rate, \ 256 .get_parent = meson_clk_pll_get_parent, \ 257 } 258 259 #define MESON_CLK_PLL(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 260 _reset, _flags) \ 261 [_id] = { \ 262 .type = MESON_CLK_PLL, \ 263 .base.name = (_name), \ 264 .u.pll.parent = (_parent), \ 265 .u.pll.enable = _enable, \ 266 .u.pll.m = _m, \ 267 .u.pll.n = _n, \ 268 .u.pll.frac = _frac, \ 269 .u.pll.l = _l, \ 270 .u.pll.reset = _reset, \ 271 .u.pll.flags = (_flags), \ 272 .get_rate = meson_clk_pll_get_rate, \ 273 .get_parent = meson_clk_pll_get_parent, \ 274 } 275 276 /* 277 * MPLL clocks 278 */ 279 280 struct meson_clk_mpll { 281 struct meson_clk_pll_reg sdm; 282 struct meson_clk_pll_reg sdm_enable; 283 struct meson_clk_pll_reg n2; 284 struct meson_clk_pll_reg ssen; 285 const char *parent; 286 uint32_t flags; 287 }; 288 289 u_int meson_clk_mpll_get_rate(struct meson_clk_softc *, 290 struct meson_clk_clk *); 291 const char *meson_clk_mpll_get_parent(struct meson_clk_softc *, 292 struct meson_clk_clk *); 293 294 #define MESON_CLK_MPLL(_id, _name, _parent, _sdm, _sdm_enable, _n2, \ 295 _ssen, _flags) \ 296 [_id] = { \ 297 .type = MESON_CLK_MPLL, \ 298 .base.name = (_name), \ 299 .u.mpll.parent = (_parent), \ 300 .u.mpll.sdm = _sdm, \ 301 .u.mpll.sdm_enable = _sdm_enable, \ 302 .u.mpll.n2 = _n2, \ 303 .u.mpll.ssen = _ssen, \ 304 .u.mpll.flags = (_flags), \ 305 .get_rate = meson_clk_mpll_get_rate, \ 306 .get_parent = meson_clk_mpll_get_parent, \ 307 } 308 309 310 311 struct meson_clk_clk { 312 struct clk base; 313 enum meson_clk_clktype type; 314 union { 315 struct meson_clk_fixed fixed; 316 struct meson_clk_gate gate; 317 struct meson_clk_div div; 318 struct meson_clk_fixed_factor fixed_factor; 319 struct meson_clk_mux mux; 320 struct meson_clk_pll pll; 321 struct meson_clk_mpll mpll; 322 } u; 323 324 int (*enable)(struct meson_clk_softc *, 325 struct meson_clk_clk *, int); 326 u_int (*get_rate)(struct meson_clk_softc *, 327 struct meson_clk_clk *); 328 int (*set_rate)(struct meson_clk_softc *, 329 struct meson_clk_clk *, u_int); 330 u_int (*round_rate)(struct meson_clk_softc *, 331 struct meson_clk_clk *, u_int); 332 const char * (*get_parent)(struct meson_clk_softc *, 333 struct meson_clk_clk *); 334 int (*set_parent)(struct meson_clk_softc *, 335 struct meson_clk_clk *, 336 const char *); 337 }; 338 339 struct meson_clk_softc { 340 device_t sc_dev; 341 int sc_phandle; 342 343 bus_space_tag_t sc_bst; 344 bus_space_handle_t sc_bsh; 345 346 struct syscon *sc_syscon; 347 348 struct clk_domain sc_clkdom; 349 350 struct meson_clk_reset *sc_resets; 351 u_int sc_nresets; 352 353 struct meson_clk_clk *sc_clks; 354 u_int sc_nclks; 355 }; 356 357 void meson_clk_attach(struct meson_clk_softc *); 358 struct meson_clk_clk *meson_clk_clock_find(struct meson_clk_softc *, 359 const char *); 360 void meson_clk_print(struct meson_clk_softc *); 361 362 void meson_clk_lock(struct meson_clk_softc *); 363 void meson_clk_unlock(struct meson_clk_softc *); 364 uint32_t meson_clk_read(struct meson_clk_softc *, bus_size_t); 365 void meson_clk_write(struct meson_clk_softc *, bus_size_t, uint32_t); 366 367 #define CLK_LOCK meson_clk_lock 368 #define CLK_UNLOCK meson_clk_unlock 369 #define CLK_READ meson_clk_read 370 #define CLK_WRITE meson_clk_write 371 372 #endif /* _ARM_MESON_CLK_H */ 373