1 /* $NetBSD: rk_cru.h,v 1.2 2018/06/30 17:54:07 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 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_RK_CRU_H 30 #define _ARM_RK_CRU_H 31 32 #include <dev/clk/clk_backend.h> 33 #include <dev/fdt/syscon.h> 34 35 struct rk_cru_softc; 36 struct rk_cru_clk; 37 38 /* 39 * Clocks 40 */ 41 42 enum rk_cru_clktype { 43 RK_CRU_UNKNOWN, 44 RK_CRU_PLL, 45 RK_CRU_ARM, 46 RK_CRU_COMPOSITE, 47 RK_CRU_GATE, 48 RK_CRU_MUX, 49 }; 50 51 /* PLL clocks */ 52 53 struct rk_cru_pll_rate { 54 u_int rate; 55 u_int refdiv; 56 u_int fbdiv; 57 u_int postdiv1; 58 u_int postdiv2; 59 u_int dsmpd; 60 u_int fracdiv; 61 }; 62 63 #define RK_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _fracdiv) \ 64 { \ 65 .rate = (_rate), \ 66 .refdiv = (_refdiv), \ 67 .fbdiv = (_fbdiv), \ 68 .postdiv1 = (_postdiv1), \ 69 .postdiv2 = (_postdiv2), \ 70 .dsmpd = (_dsmpd), \ 71 .fracdiv = (_fracdiv), \ 72 } 73 74 struct rk_cru_pll { 75 bus_size_t con_base; 76 bus_size_t mode_reg; 77 uint32_t mode_mask; 78 uint32_t lock_mask; 79 const struct rk_cru_pll_rate *rates; 80 u_int nrates; 81 const char *parent; 82 }; 83 84 u_int rk_cru_pll_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); 85 int rk_cru_pll_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); 86 const char *rk_cru_pll_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); 87 88 #define RK_PLL(_id, _name, _parent, _con_base, _mode_reg, _mode_mask, _lock_mask, _rates) \ 89 { \ 90 .id = (_id), \ 91 .type = RK_CRU_PLL, \ 92 .base.name = (_name), \ 93 .base.flags = 0, \ 94 .u.pll.parent = (_parent), \ 95 .u.pll.con_base = (_con_base), \ 96 .u.pll.mode_reg = (_mode_reg), \ 97 .u.pll.mode_mask = (_mode_mask), \ 98 .u.pll.lock_mask = (_lock_mask), \ 99 .u.pll.rates = (_rates), \ 100 .u.pll.nrates = __arraycount(_rates), \ 101 .get_rate = rk_cru_pll_get_rate, \ 102 .set_rate = rk_cru_pll_set_rate, \ 103 .get_parent = rk_cru_pll_get_parent, \ 104 } 105 106 /* ARM clocks */ 107 108 struct rk_cru_arm_rate { 109 u_int rate; 110 u_int div; 111 }; 112 113 #define RK_ARM_RATE(_rate, _div) \ 114 { \ 115 .rate = (_rate), \ 116 .div = (_div), \ 117 } 118 119 struct rk_cru_arm { 120 bus_size_t reg; 121 uint32_t mux_mask; 122 u_int mux_main; 123 u_int mux_alt; 124 uint32_t div_mask; 125 const char **parents; 126 u_int nparents; 127 const struct rk_cru_arm_rate *rates; 128 u_int nrates; 129 }; 130 131 u_int rk_cru_arm_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); 132 int rk_cru_arm_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); 133 const char *rk_cru_arm_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); 134 int rk_cru_arm_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); 135 136 #define RK_ARM(_id, _name, _parents, _reg, _mux_mask, _mux_main, _mux_alt, _div_mask, _rates) \ 137 { \ 138 .id = (_id), \ 139 .type = RK_CRU_ARM, \ 140 .base.name = (_name), \ 141 .base.flags = 0, \ 142 .u.arm.parents = (_parents), \ 143 .u.arm.nparents = __arraycount(_parents), \ 144 .u.arm.reg = (_reg), \ 145 .u.arm.mux_mask = (_mux_mask), \ 146 .u.arm.mux_main = (_mux_main), \ 147 .u.arm.mux_alt = (_mux_alt), \ 148 .u.arm.div_mask = (_div_mask), \ 149 .u.arm.rates = (_rates), \ 150 .u.arm.nrates = __arraycount(_rates), \ 151 .get_rate = rk_cru_arm_get_rate, \ 152 .set_rate = rk_cru_arm_set_rate, \ 153 .get_parent = rk_cru_arm_get_parent, \ 154 .set_parent = rk_cru_arm_set_parent, \ 155 } 156 157 /* Composite clocks */ 158 159 struct rk_cru_composite { 160 bus_size_t muxdiv_reg; 161 uint32_t mux_mask; 162 uint32_t div_mask; 163 bus_size_t gate_reg; 164 uint32_t gate_mask; 165 const char **parents; 166 u_int nparents; 167 u_int flags; 168 #define RK_COMPOSITE_ROUND_DOWN 0x01 169 }; 170 171 int rk_cru_composite_enable(struct rk_cru_softc *, struct rk_cru_clk *, int); 172 u_int rk_cru_composite_get_rate(struct rk_cru_softc *, struct rk_cru_clk *); 173 int rk_cru_composite_set_rate(struct rk_cru_softc *, struct rk_cru_clk *, u_int); 174 const char *rk_cru_composite_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); 175 int rk_cru_composite_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); 176 177 #define RK_COMPOSITE(_id, _name, _parents, _muxdiv_reg, _mux_mask, _div_mask, _gate_reg, _gate_mask, _flags) \ 178 { \ 179 .id = (_id), \ 180 .type = RK_CRU_COMPOSITE, \ 181 .base.name = (_name), \ 182 .base.flags = 0, \ 183 .u.composite.parents = (_parents), \ 184 .u.composite.nparents = __arraycount(_parents), \ 185 .u.composite.muxdiv_reg = (_muxdiv_reg), \ 186 .u.composite.mux_mask = (_mux_mask), \ 187 .u.composite.div_mask = (_div_mask), \ 188 .u.composite.gate_reg = (_gate_reg), \ 189 .u.composite.gate_mask = (_gate_mask), \ 190 .u.composite.flags = (_flags), \ 191 .enable = rk_cru_composite_enable, \ 192 .get_rate = rk_cru_composite_get_rate, \ 193 .set_rate = rk_cru_composite_set_rate, \ 194 .get_parent = rk_cru_composite_get_parent, \ 195 .set_parent = rk_cru_composite_set_parent, \ 196 } 197 198 /* Gate clocks */ 199 200 struct rk_cru_gate { 201 bus_size_t reg; 202 uint32_t mask; 203 const char *parent; 204 }; 205 206 int rk_cru_gate_enable(struct rk_cru_softc *, 207 struct rk_cru_clk *, int); 208 const char *rk_cru_gate_get_parent(struct rk_cru_softc *, 209 struct rk_cru_clk *); 210 211 #define RK_GATE(_id, _name, _pname, _reg, _bit) \ 212 { \ 213 .id = (_id), \ 214 .type = RK_CRU_GATE, \ 215 .base.name = (_name), \ 216 .base.flags = CLK_SET_RATE_PARENT, \ 217 .u.gate.parent = (_pname), \ 218 .u.gate.reg = (_reg), \ 219 .u.gate.mask = __BIT(_bit), \ 220 .enable = rk_cru_gate_enable, \ 221 .get_parent = rk_cru_gate_get_parent, \ 222 } 223 224 /* Mux clocks */ 225 226 struct rk_cru_mux { 227 bus_size_t reg; 228 uint32_t mask; 229 const char **parents; 230 u_int nparents; 231 u_int flags; 232 #define RK_MUX_GRF 0x01 233 }; 234 235 const char *rk_cru_mux_get_parent(struct rk_cru_softc *, struct rk_cru_clk *); 236 int rk_cru_mux_set_parent(struct rk_cru_softc *, struct rk_cru_clk *, const char *); 237 238 #define RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, _flags) \ 239 { \ 240 .id = (_id), \ 241 .type = RK_CRU_MUX, \ 242 .base.name = (_name), \ 243 .base.flags = CLK_SET_RATE_PARENT, \ 244 .u.mux.parents = (_parents), \ 245 .u.mux.nparents = __arraycount(_parents), \ 246 .u.mux.reg = (_reg), \ 247 .u.mux.mask = (_mask), \ 248 .u.mux.flags = (_flags), \ 249 .set_parent = rk_cru_mux_set_parent, \ 250 .get_parent = rk_cru_mux_get_parent, \ 251 } 252 #define RK_MUX(_id, _name, _parents, _reg, _mask) \ 253 RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, 0) 254 #define RK_MUXGRF(_id, _name, _parents, _reg, _mask) \ 255 RK_MUX_FLAGS(_id, _name, _parents, _reg, _mask, RK_MUX_GRF) 256 257 /* 258 * Rockchip clock definition 259 */ 260 261 struct rk_cru_clk { 262 struct clk base; 263 u_int id; 264 enum rk_cru_clktype type; 265 union { 266 struct rk_cru_pll pll; 267 struct rk_cru_arm arm; 268 struct rk_cru_composite composite; 269 struct rk_cru_gate gate; 270 struct rk_cru_mux mux; 271 } u; 272 273 int (*enable)(struct rk_cru_softc *, 274 struct rk_cru_clk *, int); 275 u_int (*get_rate)(struct rk_cru_softc *, 276 struct rk_cru_clk *); 277 int (*set_rate)(struct rk_cru_softc *, 278 struct rk_cru_clk *, u_int); 279 u_int (*round_rate)(struct rk_cru_softc *, 280 struct rk_cru_clk *, u_int); 281 const char * (*get_parent)(struct rk_cru_softc *, 282 struct rk_cru_clk *); 283 int (*set_parent)(struct rk_cru_softc *, 284 struct rk_cru_clk *, 285 const char *); 286 }; 287 288 /* 289 * Driver state 290 */ 291 292 struct rk_cru_softc { 293 device_t sc_dev; 294 int sc_phandle; 295 bus_space_tag_t sc_bst; 296 bus_space_handle_t sc_bsh; 297 struct syscon *sc_grf; 298 299 struct clk_domain sc_clkdom; 300 301 struct rk_cru_clk *sc_clks; 302 u_int sc_nclks; 303 }; 304 305 int rk_cru_attach(struct rk_cru_softc *); 306 struct rk_cru_clk *rk_cru_clock_find(struct rk_cru_softc *, 307 const char *); 308 void rk_cru_print(struct rk_cru_softc *); 309 310 #define CRU_READ(sc, reg) \ 311 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 312 #define CRU_WRITE(sc, reg, val) \ 313 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 314 315 #define HAS_GRF(sc) ((sc)->sc_grf != NULL) 316 317 #endif /* _ARM_RK_CRU_H */ 318