1/* $NetBSD: meson_clk.h,v 1.4 2021/01/01 07:21:58 ryo 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 35struct meson_clk_softc; 36struct meson_clk_clk; 37struct meson_clk_reset; 38 39/* 40 * Resets 41 */ 42 43struct 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 58enum 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 73struct meson_clk_fixed { 74 u_int rate; 75}; 76 77u_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 92struct 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 100int meson_clk_gate_enable(struct meson_clk_softc *, 101 struct meson_clk_clk *, int); 102const 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 125struct 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 135u_int meson_clk_div_get_rate(struct meson_clk_softc *, 136 struct meson_clk_clk *); 137int meson_clk_div_set_rate(struct meson_clk_softc *, 138 struct meson_clk_clk *, u_int); 139const 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 159struct meson_clk_fixed_factor { 160 const char *parent; 161 u_int div; 162 u_int mult; 163}; 164 165u_int meson_clk_fixed_factor_get_rate(struct meson_clk_softc *, 166 struct meson_clk_clk *); 167int meson_clk_fixed_factor_set_rate(struct meson_clk_softc *, 168 struct meson_clk_clk *, u_int); 169const 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 188struct 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 196const char *meson_clk_mux_get_parent(struct meson_clk_softc *, 197 struct meson_clk_clk *); 198 199#define MESON_CLK_MUX_RATE(_id, _name, _parents, _reg, _sel, \ 200 _getratefn, _setratefn, _flags) \ 201 [_id] = { \ 202 .type = MESON_CLK_MUX, \ 203 .base.name = (_name), \ 204 .base.flags = 0, \ 205 .u.mux.parents = (_parents), \ 206 .u.mux.nparents = __arraycount(_parents), \ 207 .u.mux.reg = (_reg), \ 208 .u.mux.sel = (_sel), \ 209 .u.mux.flags = (_flags), \ 210 .get_rate = _getratefn, \ 211 .set_rate = _setratefn, \ 212 .get_parent = meson_clk_mux_get_parent, \ 213 } 214 215#define MESON_CLK_MUX(_id, _name, _parents, _reg, _sel, _flags) \ 216 [_id] = { \ 217 .type = MESON_CLK_MUX, \ 218 .base.name = (_name), \ 219 .base.flags = CLK_SET_RATE_PARENT, \ 220 .u.mux.parents = (_parents), \ 221 .u.mux.nparents = __arraycount(_parents), \ 222 .u.mux.reg = (_reg), \ 223 .u.mux.sel = (_sel), \ 224 .u.mux.flags = (_flags), \ 225 .get_parent = meson_clk_mux_get_parent, \ 226 } 227 228/* 229 * PLL clocks 230 */ 231 232struct meson_clk_pll_reg { 233 bus_size_t reg; 234 uint32_t mask; 235}; 236 237#define MESON_CLK_PLL_REG(_reg, _mask) \ 238 { .reg = (_reg), .mask = (_mask) } 239#define MESON_CLK_PLL_REG_INVALID MESON_CLK_PLL_REG(0,0) 240 241struct meson_clk_pll { 242 struct meson_clk_pll_reg enable; 243 struct meson_clk_pll_reg m; 244 struct meson_clk_pll_reg n; 245 struct meson_clk_pll_reg frac; 246 struct meson_clk_pll_reg l; 247 struct meson_clk_pll_reg reset; 248 const char *parent; 249 uint32_t flags; 250}; 251 252u_int meson_clk_pll_get_rate(struct meson_clk_softc *, 253 struct meson_clk_clk *); 254int meson_clk_pll_set_rate(struct meson_clk_softc *, 255 struct meson_clk_clk *, u_int new_rate); 256const char *meson_clk_pll_get_parent(struct meson_clk_softc *, 257 struct meson_clk_clk *); 258int meson_clk_pll_wait_lock(struct meson_clk_softc *sc, 259 struct meson_clk_pll *pll); 260 261 262#define MESON_CLK_PLL_RATE(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 263 _reset, _setratefn, _flags) \ 264 [_id] = { \ 265 .type = MESON_CLK_PLL, \ 266 .base.name = (_name), \ 267 .u.pll.parent = (_parent), \ 268 .u.pll.enable = _enable, \ 269 .u.pll.m = _m, \ 270 .u.pll.n = _n, \ 271 .u.pll.frac = _frac, \ 272 .u.pll.l = _l, \ 273 .u.pll.reset = _reset, \ 274 .u.pll.flags = (_flags), \ 275 .set_rate = (_setratefn), \ 276 .get_rate = meson_clk_pll_get_rate, \ 277 .get_parent = meson_clk_pll_get_parent, \ 278 } 279 280#define MESON_CLK_PLL(_id, _name, _parent, _enable, _m, _n, _frac, _l, \ 281 _reset, _flags) \ 282 [_id] = { \ 283 .type = MESON_CLK_PLL, \ 284 .base.name = (_name), \ 285 .u.pll.parent = (_parent), \ 286 .u.pll.enable = _enable, \ 287 .u.pll.m = _m, \ 288 .u.pll.n = _n, \ 289 .u.pll.frac = _frac, \ 290 .u.pll.l = _l, \ 291 .u.pll.reset = _reset, \ 292 .u.pll.flags = (_flags), \ 293 .get_rate = meson_clk_pll_get_rate, \ 294 .get_parent = meson_clk_pll_get_parent, \ 295 } 296 297/* 298 * MPLL clocks 299 */ 300 301struct meson_clk_mpll { 302 struct meson_clk_pll_reg sdm; 303 struct meson_clk_pll_reg sdm_enable; 304 struct meson_clk_pll_reg n2; 305 struct meson_clk_pll_reg ssen; 306 const char *parent; 307 uint32_t flags; 308}; 309 310u_int meson_clk_mpll_get_rate(struct meson_clk_softc *, 311 struct meson_clk_clk *); 312const char *meson_clk_mpll_get_parent(struct meson_clk_softc *, 313 struct meson_clk_clk *); 314 315#define MESON_CLK_MPLL(_id, _name, _parent, _sdm, _sdm_enable, _n2, \ 316 _ssen, _flags) \ 317 [_id] = { \ 318 .type = MESON_CLK_MPLL, \ 319 .base.name = (_name), \ 320 .u.mpll.parent = (_parent), \ 321 .u.mpll.sdm = _sdm, \ 322 .u.mpll.sdm_enable = _sdm_enable, \ 323 .u.mpll.n2 = _n2, \ 324 .u.mpll.ssen = _ssen, \ 325 .u.mpll.flags = (_flags), \ 326 .get_rate = meson_clk_mpll_get_rate, \ 327 .get_parent = meson_clk_mpll_get_parent, \ 328 } 329 330 331 332struct meson_clk_clk { 333 struct clk base; 334 enum meson_clk_clktype type; 335 union { 336 struct meson_clk_fixed fixed; 337 struct meson_clk_gate gate; 338 struct meson_clk_div div; 339 struct meson_clk_fixed_factor fixed_factor; 340 struct meson_clk_mux mux; 341 struct meson_clk_pll pll; 342 struct meson_clk_mpll mpll; 343 } u; 344 345 int (*enable)(struct meson_clk_softc *, 346 struct meson_clk_clk *, int); 347 u_int (*get_rate)(struct meson_clk_softc *, 348 struct meson_clk_clk *); 349 int (*set_rate)(struct meson_clk_softc *, 350 struct meson_clk_clk *, u_int); 351 u_int (*round_rate)(struct meson_clk_softc *, 352 struct meson_clk_clk *, u_int); 353 const char * (*get_parent)(struct meson_clk_softc *, 354 struct meson_clk_clk *); 355 int (*set_parent)(struct meson_clk_softc *, 356 struct meson_clk_clk *, 357 const char *); 358}; 359 360struct meson_clk_softc { 361 device_t sc_dev; 362 int sc_phandle; 363 364 bus_space_tag_t sc_bst; 365 bus_space_handle_t sc_bsh; 366 367 struct syscon *sc_syscon; 368 369 struct clk_domain sc_clkdom; 370 371 struct meson_clk_reset *sc_resets; 372 u_int sc_nresets; 373 374 struct meson_clk_clk *sc_clks; 375 u_int sc_nclks; 376}; 377 378void meson_clk_attach(struct meson_clk_softc *); 379struct meson_clk_clk *meson_clk_clock_find(struct meson_clk_softc *, 380 const char *); 381void meson_clk_print(struct meson_clk_softc *); 382 383void meson_clk_lock(struct meson_clk_softc *); 384void meson_clk_unlock(struct meson_clk_softc *); 385uint32_t meson_clk_read(struct meson_clk_softc *, bus_size_t); 386void meson_clk_write(struct meson_clk_softc *, bus_size_t, uint32_t); 387 388#define CLK_LOCK meson_clk_lock 389#define CLK_UNLOCK meson_clk_unlock 390#define CLK_READ meson_clk_read 391#define CLK_WRITE meson_clk_write 392#define CLK_WRITE_BITS(sc, reg, mask, val) \ 393 do { \ 394 uint32_t _cwb_tmp_ = CLK_READ((sc), (reg)); \ 395 _cwb_tmp_ &= ~(mask); \ 396 _cwb_tmp_ |= __SHIFTIN((val), (mask)); \ 397 CLK_WRITE((sc), (reg), _cwb_tmp_); \ 398 } while (0 /*CONSTCOND*/) 399 400#endif /* _ARM_MESON_CLK_H */ 401