1 1.4 ryo /* $NetBSD: meson_clk.h,v 1.4 2021/01/01 07:21:58 ryo Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2017-2019 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #ifndef _ARM_MESON_CLK_H 30 1.1 jmcneill #define _ARM_MESON_CLK_H 31 1.1 jmcneill 32 1.1 jmcneill #include <dev/clk/clk_backend.h> 33 1.3 jmcneill #include <dev/fdt/syscon.h> 34 1.1 jmcneill 35 1.1 jmcneill struct meson_clk_softc; 36 1.1 jmcneill struct meson_clk_clk; 37 1.1 jmcneill struct meson_clk_reset; 38 1.1 jmcneill 39 1.1 jmcneill /* 40 1.1 jmcneill * Resets 41 1.1 jmcneill */ 42 1.1 jmcneill 43 1.1 jmcneill struct meson_clk_reset { 44 1.1 jmcneill bus_size_t reg; 45 1.1 jmcneill uint32_t mask; 46 1.1 jmcneill }; 47 1.1 jmcneill 48 1.1 jmcneill #define MESON_CLK_RESET(_id, _reg, _bit) \ 49 1.1 jmcneill [_id] = { \ 50 1.1 jmcneill .reg = (_reg), \ 51 1.1 jmcneill .mask = __BIT(_bit), \ 52 1.1 jmcneill } 53 1.1 jmcneill 54 1.1 jmcneill /* 55 1.1 jmcneill * Clocks 56 1.1 jmcneill */ 57 1.1 jmcneill 58 1.1 jmcneill enum meson_clk_clktype { 59 1.1 jmcneill MESON_CLK_UNKNOWN, 60 1.1 jmcneill MESON_CLK_FIXED, 61 1.1 jmcneill MESON_CLK_GATE, 62 1.1 jmcneill MESON_CLK_PLL, 63 1.1 jmcneill MESON_CLK_MPLL, 64 1.1 jmcneill MESON_CLK_DIV, 65 1.1 jmcneill MESON_CLK_FIXED_FACTOR, 66 1.1 jmcneill MESON_CLK_MUX, 67 1.1 jmcneill }; 68 1.1 jmcneill 69 1.1 jmcneill /* 70 1.1 jmcneill * Fixed clocks 71 1.1 jmcneill */ 72 1.1 jmcneill 73 1.1 jmcneill struct meson_clk_fixed { 74 1.1 jmcneill u_int rate; 75 1.1 jmcneill }; 76 1.1 jmcneill 77 1.1 jmcneill u_int meson_clk_fixed_get_rate(struct meson_clk_softc *, struct meson_clk_clk *); 78 1.1 jmcneill 79 1.1 jmcneill #define MESON_CLK_FIXED(_id, _name, _rate) \ 80 1.1 jmcneill [_id] = { \ 81 1.1 jmcneill .type = MESON_CLK_FIXED, \ 82 1.1 jmcneill .base.name = (_name), \ 83 1.1 jmcneill .base.flags = 0, \ 84 1.1 jmcneill .u.fixed.rate = (_rate), \ 85 1.1 jmcneill .get_rate = meson_clk_fixed_get_rate, \ 86 1.1 jmcneill } 87 1.1 jmcneill 88 1.1 jmcneill /* 89 1.1 jmcneill * Gate clocks 90 1.1 jmcneill */ 91 1.1 jmcneill 92 1.1 jmcneill struct meson_clk_gate { 93 1.1 jmcneill bus_size_t reg; 94 1.1 jmcneill uint32_t mask; 95 1.1 jmcneill const char *parent; 96 1.1 jmcneill uint32_t flags; 97 1.1 jmcneill #define MESON_CLK_GATE_SET_TO_DISABLE __BIT(0) 98 1.1 jmcneill }; 99 1.1 jmcneill 100 1.1 jmcneill int meson_clk_gate_enable(struct meson_clk_softc *, 101 1.1 jmcneill struct meson_clk_clk *, int); 102 1.1 jmcneill const char *meson_clk_gate_get_parent(struct meson_clk_softc *, 103 1.1 jmcneill struct meson_clk_clk *); 104 1.1 jmcneill 105 1.1 jmcneill #define MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, _flags) \ 106 1.1 jmcneill [_id] = { \ 107 1.1 jmcneill .type = MESON_CLK_GATE, \ 108 1.1 jmcneill .base.name = (_name), \ 109 1.1 jmcneill .base.flags = CLK_SET_RATE_PARENT, \ 110 1.1 jmcneill .u.gate.parent = (_pname), \ 111 1.1 jmcneill .u.gate.reg = (_reg), \ 112 1.1 jmcneill .u.gate.mask = __BIT(_bit), \ 113 1.1 jmcneill .u.gate.flags = (_flags), \ 114 1.1 jmcneill .enable = meson_clk_gate_enable, \ 115 1.1 jmcneill .get_parent = meson_clk_gate_get_parent, \ 116 1.1 jmcneill } 117 1.1 jmcneill 118 1.1 jmcneill #define MESON_CLK_GATE(_id, _name, _pname, _reg, _bit) \ 119 1.1 jmcneill MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, 0) 120 1.1 jmcneill 121 1.1 jmcneill /* 122 1.1 jmcneill * Divider clocks 123 1.1 jmcneill */ 124 1.1 jmcneill 125 1.1 jmcneill struct meson_clk_div { 126 1.1 jmcneill bus_size_t reg; 127 1.1 jmcneill const char *parent; 128 1.1 jmcneill uint32_t div; 129 1.1 jmcneill uint32_t flags; 130 1.1 jmcneill #define MESON_CLK_DIV_POWER_OF_TWO __BIT(0) 131 1.1 jmcneill #define MESON_CLK_DIV_SET_RATE_PARENT __BIT(1) 132 1.1 jmcneill #define MESON_CLK_DIV_CPU_SCALE_TABLE __BIT(2) 133 1.1 jmcneill }; 134 1.1 jmcneill 135 1.1 jmcneill u_int meson_clk_div_get_rate(struct meson_clk_softc *, 136 1.1 jmcneill struct meson_clk_clk *); 137 1.1 jmcneill int meson_clk_div_set_rate(struct meson_clk_softc *, 138 1.1 jmcneill struct meson_clk_clk *, u_int); 139 1.1 jmcneill const char *meson_clk_div_get_parent(struct meson_clk_softc *, 140 1.1 jmcneill struct meson_clk_clk *); 141 1.1 jmcneill 142 1.1 jmcneill #define MESON_CLK_DIV(_id, _name, _parent, _reg, _div, _flags) \ 143 1.1 jmcneill [_id] = { \ 144 1.1 jmcneill .type = MESON_CLK_DIV, \ 145 1.1 jmcneill .base.name = (_name), \ 146 1.1 jmcneill .u.div.reg = (_reg), \ 147 1.1 jmcneill .u.div.parent = (_parent), \ 148 1.1 jmcneill .u.div.div = (_div), \ 149 1.1 jmcneill .u.div.flags = (_flags), \ 150 1.1 jmcneill .get_rate = meson_clk_div_get_rate, \ 151 1.1 jmcneill .set_rate = meson_clk_div_set_rate, \ 152 1.1 jmcneill .get_parent = meson_clk_div_get_parent, \ 153 1.1 jmcneill } 154 1.1 jmcneill 155 1.1 jmcneill /* 156 1.1 jmcneill * Fixed-factor clocks 157 1.1 jmcneill */ 158 1.1 jmcneill 159 1.1 jmcneill struct meson_clk_fixed_factor { 160 1.1 jmcneill const char *parent; 161 1.1 jmcneill u_int div; 162 1.1 jmcneill u_int mult; 163 1.1 jmcneill }; 164 1.1 jmcneill 165 1.1 jmcneill u_int meson_clk_fixed_factor_get_rate(struct meson_clk_softc *, 166 1.1 jmcneill struct meson_clk_clk *); 167 1.1 jmcneill int meson_clk_fixed_factor_set_rate(struct meson_clk_softc *, 168 1.1 jmcneill struct meson_clk_clk *, u_int); 169 1.1 jmcneill const char *meson_clk_fixed_factor_get_parent(struct meson_clk_softc *, 170 1.1 jmcneill struct meson_clk_clk *); 171 1.1 jmcneill 172 1.1 jmcneill #define MESON_CLK_FIXED_FACTOR(_id, _name, _parent, _div, _mult) \ 173 1.1 jmcneill [_id] = { \ 174 1.1 jmcneill .type = MESON_CLK_FIXED_FACTOR, \ 175 1.1 jmcneill .base.name = (_name), \ 176 1.1 jmcneill .u.fixed_factor.parent = (_parent), \ 177 1.1 jmcneill .u.fixed_factor.div = (_div), \ 178 1.1 jmcneill .u.fixed_factor.mult = (_mult), \ 179 1.1 jmcneill .get_rate = meson_clk_fixed_factor_get_rate, \ 180 1.1 jmcneill .get_parent = meson_clk_fixed_factor_get_parent, \ 181 1.1 jmcneill .set_rate = meson_clk_fixed_factor_set_rate, \ 182 1.1 jmcneill } 183 1.1 jmcneill 184 1.1 jmcneill /* 185 1.1 jmcneill * Mux clocks 186 1.1 jmcneill */ 187 1.1 jmcneill 188 1.1 jmcneill struct meson_clk_mux { 189 1.1 jmcneill bus_size_t reg; 190 1.1 jmcneill const char **parents; 191 1.1 jmcneill u_int nparents; 192 1.1 jmcneill uint32_t sel; 193 1.1 jmcneill uint32_t flags; 194 1.1 jmcneill }; 195 1.1 jmcneill 196 1.1 jmcneill const char *meson_clk_mux_get_parent(struct meson_clk_softc *, 197 1.1 jmcneill struct meson_clk_clk *); 198 1.1 jmcneill 199 1.4 ryo #define MESON_CLK_MUX_RATE(_id, _name, _parents, _reg, _sel, \ 200 1.4 ryo _getratefn, _setratefn, _flags) \ 201 1.4 ryo [_id] = { \ 202 1.4 ryo .type = MESON_CLK_MUX, \ 203 1.4 ryo .base.name = (_name), \ 204 1.4 ryo .base.flags = 0, \ 205 1.4 ryo .u.mux.parents = (_parents), \ 206 1.4 ryo .u.mux.nparents = __arraycount(_parents), \ 207 1.4 ryo .u.mux.reg = (_reg), \ 208 1.4 ryo .u.mux.sel = (_sel), \ 209 1.4 ryo .u.mux.flags = (_flags), \ 210 1.4 ryo .get_rate = _getratefn, \ 211 1.4 ryo .set_rate = _setratefn, \ 212 1.4 ryo .get_parent = meson_clk_mux_get_parent, \ 213 1.4 ryo } 214 1.4 ryo 215 1.1 jmcneill #define MESON_CLK_MUX(_id, _name, _parents, _reg, _sel, _flags) \ 216 1.1 jmcneill [_id] = { \ 217 1.1 jmcneill .type = MESON_CLK_MUX, \ 218 1.1 jmcneill .base.name = (_name), \ 219 1.2 jmcneill .base.flags = CLK_SET_RATE_PARENT, \ 220 1.1 jmcneill .u.mux.parents = (_parents), \ 221 1.1 jmcneill .u.mux.nparents = __arraycount(_parents), \ 222 1.1 jmcneill .u.mux.reg = (_reg), \ 223 1.1 jmcneill .u.mux.sel = (_sel), \ 224 1.1 jmcneill .u.mux.flags = (_flags), \ 225 1.1 jmcneill .get_parent = meson_clk_mux_get_parent, \ 226 1.1 jmcneill } 227 1.1 jmcneill 228 1.1 jmcneill /* 229 1.1 jmcneill * PLL clocks 230 1.1 jmcneill */ 231 1.1 jmcneill 232 1.1 jmcneill struct meson_clk_pll_reg { 233 1.1 jmcneill bus_size_t reg; 234 1.1 jmcneill uint32_t mask; 235 1.1 jmcneill }; 236 1.1 jmcneill 237 1.1 jmcneill #define MESON_CLK_PLL_REG(_reg, _mask) \ 238 1.1 jmcneill { .reg = (_reg), .mask = (_mask) } 239 1.1 jmcneill #define MESON_CLK_PLL_REG_INVALID MESON_CLK_PLL_REG(0,0) 240 1.1 jmcneill 241 1.1 jmcneill struct meson_clk_pll { 242 1.1 jmcneill struct meson_clk_pll_reg enable; 243 1.1 jmcneill struct meson_clk_pll_reg m; 244 1.1 jmcneill struct meson_clk_pll_reg n; 245 1.1 jmcneill struct meson_clk_pll_reg frac; 246 1.1 jmcneill struct meson_clk_pll_reg l; 247 1.1 jmcneill struct meson_clk_pll_reg reset; 248 1.1 jmcneill const char *parent; 249 1.1 jmcneill uint32_t flags; 250 1.1 jmcneill }; 251 1.1 jmcneill 252 1.1 jmcneill u_int meson_clk_pll_get_rate(struct meson_clk_softc *, 253 1.1 jmcneill struct meson_clk_clk *); 254 1.4 ryo int meson_clk_pll_set_rate(struct meson_clk_softc *, 255 1.4 ryo struct meson_clk_clk *, u_int new_rate); 256 1.1 jmcneill const char *meson_clk_pll_get_parent(struct meson_clk_softc *, 257 1.1 jmcneill struct meson_clk_clk *); 258 1.4 ryo int meson_clk_pll_wait_lock(struct meson_clk_softc *sc, 259 1.4 ryo struct meson_clk_pll *pll); 260 1.4 ryo 261 1.1 jmcneill 262 1.2 jmcneill #define MESON_CLK_PLL_RATE(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 263 1.2 jmcneill _reset, _setratefn, _flags) \ 264 1.2 jmcneill [_id] = { \ 265 1.2 jmcneill .type = MESON_CLK_PLL, \ 266 1.2 jmcneill .base.name = (_name), \ 267 1.2 jmcneill .u.pll.parent = (_parent), \ 268 1.2 jmcneill .u.pll.enable = _enable, \ 269 1.2 jmcneill .u.pll.m = _m, \ 270 1.2 jmcneill .u.pll.n = _n, \ 271 1.2 jmcneill .u.pll.frac = _frac, \ 272 1.2 jmcneill .u.pll.l = _l, \ 273 1.2 jmcneill .u.pll.reset = _reset, \ 274 1.2 jmcneill .u.pll.flags = (_flags), \ 275 1.2 jmcneill .set_rate = (_setratefn), \ 276 1.2 jmcneill .get_rate = meson_clk_pll_get_rate, \ 277 1.2 jmcneill .get_parent = meson_clk_pll_get_parent, \ 278 1.2 jmcneill } 279 1.2 jmcneill 280 1.1 jmcneill #define MESON_CLK_PLL(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 281 1.1 jmcneill _reset, _flags) \ 282 1.1 jmcneill [_id] = { \ 283 1.1 jmcneill .type = MESON_CLK_PLL, \ 284 1.1 jmcneill .base.name = (_name), \ 285 1.1 jmcneill .u.pll.parent = (_parent), \ 286 1.1 jmcneill .u.pll.enable = _enable, \ 287 1.1 jmcneill .u.pll.m = _m, \ 288 1.1 jmcneill .u.pll.n = _n, \ 289 1.1 jmcneill .u.pll.frac = _frac, \ 290 1.1 jmcneill .u.pll.l = _l, \ 291 1.1 jmcneill .u.pll.reset = _reset, \ 292 1.1 jmcneill .u.pll.flags = (_flags), \ 293 1.1 jmcneill .get_rate = meson_clk_pll_get_rate, \ 294 1.1 jmcneill .get_parent = meson_clk_pll_get_parent, \ 295 1.1 jmcneill } 296 1.1 jmcneill 297 1.1 jmcneill /* 298 1.1 jmcneill * MPLL clocks 299 1.1 jmcneill */ 300 1.1 jmcneill 301 1.1 jmcneill struct meson_clk_mpll { 302 1.1 jmcneill struct meson_clk_pll_reg sdm; 303 1.1 jmcneill struct meson_clk_pll_reg sdm_enable; 304 1.1 jmcneill struct meson_clk_pll_reg n2; 305 1.1 jmcneill struct meson_clk_pll_reg ssen; 306 1.1 jmcneill const char *parent; 307 1.1 jmcneill uint32_t flags; 308 1.1 jmcneill }; 309 1.1 jmcneill 310 1.1 jmcneill u_int meson_clk_mpll_get_rate(struct meson_clk_softc *, 311 1.1 jmcneill struct meson_clk_clk *); 312 1.1 jmcneill const char *meson_clk_mpll_get_parent(struct meson_clk_softc *, 313 1.1 jmcneill struct meson_clk_clk *); 314 1.1 jmcneill 315 1.1 jmcneill #define MESON_CLK_MPLL(_id, _name, _parent, _sdm, _sdm_enable, _n2, \ 316 1.1 jmcneill _ssen, _flags) \ 317 1.1 jmcneill [_id] = { \ 318 1.1 jmcneill .type = MESON_CLK_MPLL, \ 319 1.1 jmcneill .base.name = (_name), \ 320 1.1 jmcneill .u.mpll.parent = (_parent), \ 321 1.1 jmcneill .u.mpll.sdm = _sdm, \ 322 1.1 jmcneill .u.mpll.sdm_enable = _sdm_enable, \ 323 1.1 jmcneill .u.mpll.n2 = _n2, \ 324 1.1 jmcneill .u.mpll.ssen = _ssen, \ 325 1.1 jmcneill .u.mpll.flags = (_flags), \ 326 1.1 jmcneill .get_rate = meson_clk_mpll_get_rate, \ 327 1.1 jmcneill .get_parent = meson_clk_mpll_get_parent, \ 328 1.1 jmcneill } 329 1.1 jmcneill 330 1.1 jmcneill 331 1.1 jmcneill 332 1.1 jmcneill struct meson_clk_clk { 333 1.1 jmcneill struct clk base; 334 1.1 jmcneill enum meson_clk_clktype type; 335 1.1 jmcneill union { 336 1.1 jmcneill struct meson_clk_fixed fixed; 337 1.1 jmcneill struct meson_clk_gate gate; 338 1.1 jmcneill struct meson_clk_div div; 339 1.1 jmcneill struct meson_clk_fixed_factor fixed_factor; 340 1.1 jmcneill struct meson_clk_mux mux; 341 1.1 jmcneill struct meson_clk_pll pll; 342 1.1 jmcneill struct meson_clk_mpll mpll; 343 1.1 jmcneill } u; 344 1.1 jmcneill 345 1.1 jmcneill int (*enable)(struct meson_clk_softc *, 346 1.1 jmcneill struct meson_clk_clk *, int); 347 1.1 jmcneill u_int (*get_rate)(struct meson_clk_softc *, 348 1.1 jmcneill struct meson_clk_clk *); 349 1.1 jmcneill int (*set_rate)(struct meson_clk_softc *, 350 1.1 jmcneill struct meson_clk_clk *, u_int); 351 1.1 jmcneill u_int (*round_rate)(struct meson_clk_softc *, 352 1.1 jmcneill struct meson_clk_clk *, u_int); 353 1.1 jmcneill const char * (*get_parent)(struct meson_clk_softc *, 354 1.1 jmcneill struct meson_clk_clk *); 355 1.1 jmcneill int (*set_parent)(struct meson_clk_softc *, 356 1.1 jmcneill struct meson_clk_clk *, 357 1.1 jmcneill const char *); 358 1.1 jmcneill }; 359 1.1 jmcneill 360 1.1 jmcneill struct meson_clk_softc { 361 1.1 jmcneill device_t sc_dev; 362 1.1 jmcneill int sc_phandle; 363 1.3 jmcneill 364 1.1 jmcneill bus_space_tag_t sc_bst; 365 1.1 jmcneill bus_space_handle_t sc_bsh; 366 1.1 jmcneill 367 1.3 jmcneill struct syscon *sc_syscon; 368 1.3 jmcneill 369 1.1 jmcneill struct clk_domain sc_clkdom; 370 1.1 jmcneill 371 1.1 jmcneill struct meson_clk_reset *sc_resets; 372 1.1 jmcneill u_int sc_nresets; 373 1.1 jmcneill 374 1.1 jmcneill struct meson_clk_clk *sc_clks; 375 1.1 jmcneill u_int sc_nclks; 376 1.1 jmcneill }; 377 1.1 jmcneill 378 1.3 jmcneill void meson_clk_attach(struct meson_clk_softc *); 379 1.1 jmcneill struct meson_clk_clk *meson_clk_clock_find(struct meson_clk_softc *, 380 1.1 jmcneill const char *); 381 1.1 jmcneill void meson_clk_print(struct meson_clk_softc *); 382 1.1 jmcneill 383 1.3 jmcneill void meson_clk_lock(struct meson_clk_softc *); 384 1.3 jmcneill void meson_clk_unlock(struct meson_clk_softc *); 385 1.3 jmcneill uint32_t meson_clk_read(struct meson_clk_softc *, bus_size_t); 386 1.3 jmcneill void meson_clk_write(struct meson_clk_softc *, bus_size_t, uint32_t); 387 1.3 jmcneill 388 1.3 jmcneill #define CLK_LOCK meson_clk_lock 389 1.3 jmcneill #define CLK_UNLOCK meson_clk_unlock 390 1.3 jmcneill #define CLK_READ meson_clk_read 391 1.3 jmcneill #define CLK_WRITE meson_clk_write 392 1.4 ryo #define CLK_WRITE_BITS(sc, reg, mask, val) \ 393 1.4 ryo do { \ 394 1.4 ryo uint32_t _cwb_tmp_ = CLK_READ((sc), (reg)); \ 395 1.4 ryo _cwb_tmp_ &= ~(mask); \ 396 1.4 ryo _cwb_tmp_ |= __SHIFTIN((val), (mask)); \ 397 1.4 ryo CLK_WRITE((sc), (reg), _cwb_tmp_); \ 398 1.4 ryo } while (0 /*CONSTCOND*/) 399 1.1 jmcneill 400 1.1 jmcneill #endif /* _ARM_MESON_CLK_H */ 401