1 /* $NetBSD: imx_ccm.h,v 1.1 2020/12/23 14:42:38 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2020 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_IMX_CCM_H 30 #define _ARM_IMX_CCM_H 31 32 #include <dev/clk/clk_backend.h> 33 #include <dev/fdt/syscon.h> 34 35 struct imx_ccm_softc; 36 struct imx_ccm_clk; 37 38 /* 39 * Clocks 40 */ 41 42 enum imx_ccm_clktype { 43 IMX_CCM_UNKNOWN, 44 IMX_CCM_EXTCLK, 45 IMX_CCM_GATE, 46 IMX_CCM_COMPOSITE, 47 IMX_CCM_PLL, 48 IMX_CCM_FIXED, 49 IMX_CCM_FIXED_FACTOR, 50 IMX_CCM_MUX, 51 IMX_CCM_DIV, 52 }; 53 54 /* External clocks */ 55 56 int imx_ccm_extclk_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 57 u_int imx_ccm_extclk_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 58 int imx_ccm_extclk_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 59 const char *imx_ccm_extclk_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 60 61 #define IMX_EXTCLK(_id, _name) \ 62 { \ 63 .id = (_id), \ 64 .type = IMX_CCM_EXTCLK, \ 65 .base.name = (_name), \ 66 .base.flags = 0, \ 67 .u.extclk = (_name), \ 68 .enable = imx_ccm_extclk_enable, \ 69 .get_rate = imx_ccm_extclk_get_rate, \ 70 .set_rate = imx_ccm_extclk_set_rate, \ 71 .get_parent = imx_ccm_extclk_get_parent, \ 72 } 73 74 /* Gate clocks */ 75 76 struct imx_ccm_gate { 77 bus_size_t reg; 78 uint32_t mask; 79 const char *parent; 80 }; 81 82 int imx_ccm_gate_enable(struct imx_ccm_softc *, 83 struct imx_ccm_clk *, int); 84 const char *imx_ccm_gate_get_parent(struct imx_ccm_softc *, 85 struct imx_ccm_clk *); 86 87 #define IMX_GATE(_id, _name, _pname, _reg, _mask) \ 88 IMX_GATE_INDEX(_id, 0, _name, _pname, _reg, _mask) 89 #define IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, _mask) \ 90 { \ 91 .id = (_id), \ 92 .regidx = (_regidx), \ 93 .type = IMX_CCM_GATE, \ 94 .base.name = (_name), \ 95 .base.flags = CLK_SET_RATE_PARENT, \ 96 .u.gate.parent = (_pname), \ 97 .u.gate.reg = (_reg), \ 98 .u.gate.mask = (_mask), \ 99 .enable = imx_ccm_gate_enable, \ 100 .get_parent = imx_ccm_gate_get_parent, \ 101 } 102 #define IMX_ROOT_GATE(_id, _name, _pname, _reg) \ 103 IMX_ROOT_GATE_INDEX(_id, 0, _name, _pname, _reg) 104 #define IMX_ROOT_GATE_INDEX(_id, _regidx, _name, _pname, _reg) \ 105 IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, __BITS(1,0)) 106 107 /* Composite clocks */ 108 109 struct imx_ccm_composite { 110 bus_size_t reg; 111 const char **parents; 112 u_int nparents; 113 u_int flags; 114 #define IMX_COMPOSITE_ROUND_DOWN 0x01 115 #define IMX_COMPOSITE_SET_RATE_PARENT 0x02 116 }; 117 118 int imx_ccm_composite_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 119 u_int imx_ccm_composite_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 120 int imx_ccm_composite_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 121 const char *imx_ccm_composite_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 122 int imx_ccm_composite_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *); 123 124 #define IMX_COMPOSITE(_id, _name, _parents, _reg, _flags) \ 125 IMX_COMPOSITE_INDEX(_id, 0, _name, _parents, _reg, _flags) 126 127 #define IMX_COMPOSITE_INDEX(_id, _regidx, _name, _parents, _reg, _flags) \ 128 { \ 129 .id = (_id), \ 130 .regidx = (_regidx), \ 131 .type = IMX_CCM_COMPOSITE, \ 132 .base.name = (_name), \ 133 .base.flags = 0, \ 134 .u.composite.parents = (_parents), \ 135 .u.composite.nparents = __arraycount(_parents), \ 136 .u.composite.reg = (_reg), \ 137 .u.composite.flags = (_flags), \ 138 .enable = imx_ccm_composite_enable, \ 139 .get_rate = imx_ccm_composite_get_rate, \ 140 .set_rate = imx_ccm_composite_set_rate, \ 141 .set_parent = imx_ccm_composite_set_parent, \ 142 .get_parent = imx_ccm_composite_get_parent, \ 143 } 144 145 /* PLLs */ 146 147 struct imx_ccm_pll { 148 bus_size_t reg; 149 const char *parent; 150 uint32_t div_mask; 151 u_int flags; 152 #define IMX_PLL_ARM __BIT(0) 153 #define IMX_PLL_480M_528M __BIT(1) 154 #define IMX_PLL_ENET __BIT(2) 155 }; 156 157 int imx_ccm_pll_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 158 u_int imx_ccm_pll_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 159 const char *imx_ccm_pll_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 160 161 #define IMX_PLL(_id, _name, _parent, _reg, _div_mask, _flags) \ 162 IMX_PLL_INDEX(_id, 0, _name, _parent, _reg, _div_mask, _flags) 163 #define IMX_PLL_INDEX(_id, _regidx, _name, _parent, _reg, _div_mask, _flags) \ 164 { \ 165 .id = (_id), \ 166 .regidx = (_regidx), \ 167 .type = IMX_CCM_PLL, \ 168 .base.name = (_name), \ 169 .base.flags = 0, \ 170 .u.pll.parent = (_parent), \ 171 .u.pll.reg = (_reg), \ 172 .u.pll.div_mask = (_div_mask), \ 173 .u.pll.flags = (_flags), \ 174 .enable = imx_ccm_pll_enable, \ 175 .get_rate = imx_ccm_pll_get_rate, \ 176 .get_parent = imx_ccm_pll_get_parent, \ 177 } 178 179 /* Fixed clocks */ 180 181 struct imx_ccm_fixed { 182 u_int rate; 183 }; 184 185 u_int imx_ccm_fixed_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 186 187 #define IMX_FIXED(_id, _name, _rate) \ 188 { \ 189 .id = (_id), \ 190 .type = IMX_CCM_FIXED, \ 191 .base.name = (_name), \ 192 .base.flags = 0, \ 193 .u.fixed.rate = (_rate), \ 194 .get_rate = imx_ccm_fixed_get_rate, \ 195 } 196 197 /* Fixed factor clocks */ 198 199 struct imx_ccm_fixed_factor { 200 const char *parent; 201 u_int mult; 202 u_int div; 203 }; 204 205 u_int imx_ccm_fixed_factor_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 206 int imx_ccm_fixed_factor_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 207 const char *imx_ccm_fixed_factor_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 208 209 #define IMX_FIXED_FACTOR(_id, _name, _parent, _mult, _div) \ 210 { \ 211 .id = (_id), \ 212 .type = IMX_CCM_FIXED_FACTOR, \ 213 .base.name = (_name), \ 214 .base.flags = 0, \ 215 .u.fixed_factor.parent = (_parent), \ 216 .u.fixed_factor.mult = (_mult), \ 217 .u.fixed_factor.div = (_div), \ 218 .get_rate = imx_ccm_fixed_factor_get_rate, \ 219 .set_rate = imx_ccm_fixed_factor_set_rate, \ 220 .get_parent = imx_ccm_fixed_factor_get_parent, \ 221 } 222 223 /* Mux clocks */ 224 225 struct imx_ccm_mux { 226 bus_size_t reg; 227 const char **parents; 228 u_int nparents; 229 uint32_t sel; 230 }; 231 232 const char *imx_ccm_mux_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 233 int imx_ccm_mux_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *); 234 235 #define IMX_MUX(_id, _name, _parents, _reg, _sel) \ 236 IMX_MUX_INDEX(_id, 0, _name, _parents, _reg, _sel) 237 238 #define IMX_MUX_INDEX(_id, _regidx, _name, _parents, _reg, _sel) \ 239 { \ 240 .id = (_id), \ 241 .regidx = (_regidx), \ 242 .type = IMX_CCM_MUX, \ 243 .base.name = (_name), \ 244 .base.flags = CLK_SET_RATE_PARENT, \ 245 .u.mux.parents = (_parents), \ 246 .u.mux.nparents = __arraycount(_parents), \ 247 .u.mux.reg = (_reg), \ 248 .u.mux.sel = (_sel), \ 249 .get_parent = imx_ccm_mux_get_parent, \ 250 .set_parent = imx_ccm_mux_set_parent, \ 251 } 252 253 /* Divider clocks */ 254 255 struct imx_ccm_div { 256 bus_size_t reg; 257 const char *parent; 258 uint32_t mask; 259 u_int flags; 260 #define IMX_DIV_SET_RATE_PARENT __BIT(0) 261 #define IMX_DIV_ROUND_DOWN __BIT(1) 262 }; 263 264 u_int imx_ccm_div_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 265 int imx_ccm_div_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 266 const char *imx_ccm_div_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 267 268 #define IMX_DIV(_id, _name, _parent, _reg, _mask, _flags) \ 269 IMX_DIV_INDEX(_id, 0, _name, _parent, _reg, _mask, _flags) 270 #define IMX_DIV_INDEX(_id, _regidx, _name, _parent, _reg, _mask, _flags) \ 271 { \ 272 .id = (_id), \ 273 .regidx = (_regidx), \ 274 .type = IMX_CCM_DIV, \ 275 .base.name = (_name), \ 276 .base.flags = 0, \ 277 .u.div.parent = (_parent), \ 278 .u.div.reg = (_reg), \ 279 .u.div.mask = (_mask), \ 280 .u.div.flags = (_flags), \ 281 .get_rate = imx_ccm_div_get_rate, \ 282 .set_rate = imx_ccm_div_set_rate, \ 283 .get_parent = imx_ccm_div_get_parent, \ 284 } 285 286 /* 287 * IMX clock definition 288 */ 289 290 struct imx_ccm_clk { 291 struct clk base; 292 u_int id; 293 u_int regidx; 294 enum imx_ccm_clktype type; 295 union { 296 struct imx_ccm_gate gate; 297 struct imx_ccm_composite composite; 298 struct imx_ccm_pll pll; 299 struct imx_ccm_fixed fixed; 300 struct imx_ccm_fixed_factor fixed_factor; 301 struct imx_ccm_mux mux; 302 struct imx_ccm_div div; 303 const char *extclk; 304 } u; 305 306 int (*enable)(struct imx_ccm_softc *, 307 struct imx_ccm_clk *, int); 308 u_int (*get_rate)(struct imx_ccm_softc *, 309 struct imx_ccm_clk *); 310 int (*set_rate)(struct imx_ccm_softc *, 311 struct imx_ccm_clk *, u_int); 312 u_int (*round_rate)(struct imx_ccm_softc *, 313 struct imx_ccm_clk *, u_int); 314 const char * (*get_parent)(struct imx_ccm_softc *, 315 struct imx_ccm_clk *); 316 int (*set_parent)(struct imx_ccm_softc *, 317 struct imx_ccm_clk *, 318 const char *); 319 }; 320 321 /* 322 * Driver state 323 */ 324 325 struct imx_ccm_softc { 326 device_t sc_dev; 327 int sc_phandle; 328 bus_space_tag_t sc_bst; 329 bus_space_handle_t sc_bsh[2]; 330 331 bus_addr_t sc_baseaddr; 332 333 struct clk_domain sc_clkdom; 334 335 struct imx_ccm_clk *sc_clks; 336 u_int sc_nclks; 337 }; 338 339 int imx_ccm_attach(struct imx_ccm_softc *); 340 struct imx_ccm_clk *imx_ccm_clock_find(struct imx_ccm_softc *, 341 const char *); 342 void imx_ccm_print(struct imx_ccm_softc *); 343 344 extern const struct clk_funcs imx_ccm_clock_funcs; 345 346 #define CCM_READ(sc, idx, reg) \ 347 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg)) 348 #define CCM_WRITE(sc, idx, reg, val) \ 349 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg), (val)) 350 351 #endif /* _ARM_IMX_CCM_H */ 352