1 1.1 skrll /* $NetBSD: imx_ccm.h,v 1.1 2020/12/23 14:42:38 skrll Exp $ */ 2 1.1 skrll 3 1.1 skrll /*- 4 1.1 skrll * Copyright (c) 2020 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 skrll * All rights reserved. 6 1.1 skrll * 7 1.1 skrll * Redistribution and use in source and binary forms, with or without 8 1.1 skrll * modification, are permitted provided that the following conditions 9 1.1 skrll * are met: 10 1.1 skrll * 1. Redistributions of source code must retain the above copyright 11 1.1 skrll * notice, this list of conditions and the following disclaimer. 12 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 skrll * notice, this list of conditions and the following disclaimer in the 14 1.1 skrll * documentation and/or other materials provided with the distribution. 15 1.1 skrll * 16 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 skrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 skrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 skrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 skrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 skrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 skrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 skrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 skrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 skrll * SUCH DAMAGE. 27 1.1 skrll */ 28 1.1 skrll 29 1.1 skrll #ifndef _ARM_IMX_CCM_H 30 1.1 skrll #define _ARM_IMX_CCM_H 31 1.1 skrll 32 1.1 skrll #include <dev/clk/clk_backend.h> 33 1.1 skrll #include <dev/fdt/syscon.h> 34 1.1 skrll 35 1.1 skrll struct imx_ccm_softc; 36 1.1 skrll struct imx_ccm_clk; 37 1.1 skrll 38 1.1 skrll /* 39 1.1 skrll * Clocks 40 1.1 skrll */ 41 1.1 skrll 42 1.1 skrll enum imx_ccm_clktype { 43 1.1 skrll IMX_CCM_UNKNOWN, 44 1.1 skrll IMX_CCM_EXTCLK, 45 1.1 skrll IMX_CCM_GATE, 46 1.1 skrll IMX_CCM_COMPOSITE, 47 1.1 skrll IMX_CCM_PLL, 48 1.1 skrll IMX_CCM_FIXED, 49 1.1 skrll IMX_CCM_FIXED_FACTOR, 50 1.1 skrll IMX_CCM_MUX, 51 1.1 skrll IMX_CCM_DIV, 52 1.1 skrll }; 53 1.1 skrll 54 1.1 skrll /* External clocks */ 55 1.1 skrll 56 1.1 skrll int imx_ccm_extclk_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 57 1.1 skrll u_int imx_ccm_extclk_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 58 1.1 skrll int imx_ccm_extclk_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 59 1.1 skrll const char *imx_ccm_extclk_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 60 1.1 skrll 61 1.1 skrll #define IMX_EXTCLK(_id, _name) \ 62 1.1 skrll { \ 63 1.1 skrll .id = (_id), \ 64 1.1 skrll .type = IMX_CCM_EXTCLK, \ 65 1.1 skrll .base.name = (_name), \ 66 1.1 skrll .base.flags = 0, \ 67 1.1 skrll .u.extclk = (_name), \ 68 1.1 skrll .enable = imx_ccm_extclk_enable, \ 69 1.1 skrll .get_rate = imx_ccm_extclk_get_rate, \ 70 1.1 skrll .set_rate = imx_ccm_extclk_set_rate, \ 71 1.1 skrll .get_parent = imx_ccm_extclk_get_parent, \ 72 1.1 skrll } 73 1.1 skrll 74 1.1 skrll /* Gate clocks */ 75 1.1 skrll 76 1.1 skrll struct imx_ccm_gate { 77 1.1 skrll bus_size_t reg; 78 1.1 skrll uint32_t mask; 79 1.1 skrll const char *parent; 80 1.1 skrll }; 81 1.1 skrll 82 1.1 skrll int imx_ccm_gate_enable(struct imx_ccm_softc *, 83 1.1 skrll struct imx_ccm_clk *, int); 84 1.1 skrll const char *imx_ccm_gate_get_parent(struct imx_ccm_softc *, 85 1.1 skrll struct imx_ccm_clk *); 86 1.1 skrll 87 1.1 skrll #define IMX_GATE(_id, _name, _pname, _reg, _mask) \ 88 1.1 skrll IMX_GATE_INDEX(_id, 0, _name, _pname, _reg, _mask) 89 1.1 skrll #define IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, _mask) \ 90 1.1 skrll { \ 91 1.1 skrll .id = (_id), \ 92 1.1 skrll .regidx = (_regidx), \ 93 1.1 skrll .type = IMX_CCM_GATE, \ 94 1.1 skrll .base.name = (_name), \ 95 1.1 skrll .base.flags = CLK_SET_RATE_PARENT, \ 96 1.1 skrll .u.gate.parent = (_pname), \ 97 1.1 skrll .u.gate.reg = (_reg), \ 98 1.1 skrll .u.gate.mask = (_mask), \ 99 1.1 skrll .enable = imx_ccm_gate_enable, \ 100 1.1 skrll .get_parent = imx_ccm_gate_get_parent, \ 101 1.1 skrll } 102 1.1 skrll #define IMX_ROOT_GATE(_id, _name, _pname, _reg) \ 103 1.1 skrll IMX_ROOT_GATE_INDEX(_id, 0, _name, _pname, _reg) 104 1.1 skrll #define IMX_ROOT_GATE_INDEX(_id, _regidx, _name, _pname, _reg) \ 105 1.1 skrll IMX_GATE_INDEX(_id, _regidx, _name, _pname, _reg, __BITS(1,0)) 106 1.1 skrll 107 1.1 skrll /* Composite clocks */ 108 1.1 skrll 109 1.1 skrll struct imx_ccm_composite { 110 1.1 skrll bus_size_t reg; 111 1.1 skrll const char **parents; 112 1.1 skrll u_int nparents; 113 1.1 skrll u_int flags; 114 1.1 skrll #define IMX_COMPOSITE_ROUND_DOWN 0x01 115 1.1 skrll #define IMX_COMPOSITE_SET_RATE_PARENT 0x02 116 1.1 skrll }; 117 1.1 skrll 118 1.1 skrll int imx_ccm_composite_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 119 1.1 skrll u_int imx_ccm_composite_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 120 1.1 skrll int imx_ccm_composite_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 121 1.1 skrll const char *imx_ccm_composite_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 122 1.1 skrll int imx_ccm_composite_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *); 123 1.1 skrll 124 1.1 skrll #define IMX_COMPOSITE(_id, _name, _parents, _reg, _flags) \ 125 1.1 skrll IMX_COMPOSITE_INDEX(_id, 0, _name, _parents, _reg, _flags) 126 1.1 skrll 127 1.1 skrll #define IMX_COMPOSITE_INDEX(_id, _regidx, _name, _parents, _reg, _flags) \ 128 1.1 skrll { \ 129 1.1 skrll .id = (_id), \ 130 1.1 skrll .regidx = (_regidx), \ 131 1.1 skrll .type = IMX_CCM_COMPOSITE, \ 132 1.1 skrll .base.name = (_name), \ 133 1.1 skrll .base.flags = 0, \ 134 1.1 skrll .u.composite.parents = (_parents), \ 135 1.1 skrll .u.composite.nparents = __arraycount(_parents), \ 136 1.1 skrll .u.composite.reg = (_reg), \ 137 1.1 skrll .u.composite.flags = (_flags), \ 138 1.1 skrll .enable = imx_ccm_composite_enable, \ 139 1.1 skrll .get_rate = imx_ccm_composite_get_rate, \ 140 1.1 skrll .set_rate = imx_ccm_composite_set_rate, \ 141 1.1 skrll .set_parent = imx_ccm_composite_set_parent, \ 142 1.1 skrll .get_parent = imx_ccm_composite_get_parent, \ 143 1.1 skrll } 144 1.1 skrll 145 1.1 skrll /* PLLs */ 146 1.1 skrll 147 1.1 skrll struct imx_ccm_pll { 148 1.1 skrll bus_size_t reg; 149 1.1 skrll const char *parent; 150 1.1 skrll uint32_t div_mask; 151 1.1 skrll u_int flags; 152 1.1 skrll #define IMX_PLL_ARM __BIT(0) 153 1.1 skrll #define IMX_PLL_480M_528M __BIT(1) 154 1.1 skrll #define IMX_PLL_ENET __BIT(2) 155 1.1 skrll }; 156 1.1 skrll 157 1.1 skrll int imx_ccm_pll_enable(struct imx_ccm_softc *, struct imx_ccm_clk *, int); 158 1.1 skrll u_int imx_ccm_pll_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 159 1.1 skrll const char *imx_ccm_pll_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 160 1.1 skrll 161 1.1 skrll #define IMX_PLL(_id, _name, _parent, _reg, _div_mask, _flags) \ 162 1.1 skrll IMX_PLL_INDEX(_id, 0, _name, _parent, _reg, _div_mask, _flags) 163 1.1 skrll #define IMX_PLL_INDEX(_id, _regidx, _name, _parent, _reg, _div_mask, _flags) \ 164 1.1 skrll { \ 165 1.1 skrll .id = (_id), \ 166 1.1 skrll .regidx = (_regidx), \ 167 1.1 skrll .type = IMX_CCM_PLL, \ 168 1.1 skrll .base.name = (_name), \ 169 1.1 skrll .base.flags = 0, \ 170 1.1 skrll .u.pll.parent = (_parent), \ 171 1.1 skrll .u.pll.reg = (_reg), \ 172 1.1 skrll .u.pll.div_mask = (_div_mask), \ 173 1.1 skrll .u.pll.flags = (_flags), \ 174 1.1 skrll .enable = imx_ccm_pll_enable, \ 175 1.1 skrll .get_rate = imx_ccm_pll_get_rate, \ 176 1.1 skrll .get_parent = imx_ccm_pll_get_parent, \ 177 1.1 skrll } 178 1.1 skrll 179 1.1 skrll /* Fixed clocks */ 180 1.1 skrll 181 1.1 skrll struct imx_ccm_fixed { 182 1.1 skrll u_int rate; 183 1.1 skrll }; 184 1.1 skrll 185 1.1 skrll u_int imx_ccm_fixed_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 186 1.1 skrll 187 1.1 skrll #define IMX_FIXED(_id, _name, _rate) \ 188 1.1 skrll { \ 189 1.1 skrll .id = (_id), \ 190 1.1 skrll .type = IMX_CCM_FIXED, \ 191 1.1 skrll .base.name = (_name), \ 192 1.1 skrll .base.flags = 0, \ 193 1.1 skrll .u.fixed.rate = (_rate), \ 194 1.1 skrll .get_rate = imx_ccm_fixed_get_rate, \ 195 1.1 skrll } 196 1.1 skrll 197 1.1 skrll /* Fixed factor clocks */ 198 1.1 skrll 199 1.1 skrll struct imx_ccm_fixed_factor { 200 1.1 skrll const char *parent; 201 1.1 skrll u_int mult; 202 1.1 skrll u_int div; 203 1.1 skrll }; 204 1.1 skrll 205 1.1 skrll u_int imx_ccm_fixed_factor_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 206 1.1 skrll int imx_ccm_fixed_factor_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 207 1.1 skrll const char *imx_ccm_fixed_factor_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 208 1.1 skrll 209 1.1 skrll #define IMX_FIXED_FACTOR(_id, _name, _parent, _mult, _div) \ 210 1.1 skrll { \ 211 1.1 skrll .id = (_id), \ 212 1.1 skrll .type = IMX_CCM_FIXED_FACTOR, \ 213 1.1 skrll .base.name = (_name), \ 214 1.1 skrll .base.flags = 0, \ 215 1.1 skrll .u.fixed_factor.parent = (_parent), \ 216 1.1 skrll .u.fixed_factor.mult = (_mult), \ 217 1.1 skrll .u.fixed_factor.div = (_div), \ 218 1.1 skrll .get_rate = imx_ccm_fixed_factor_get_rate, \ 219 1.1 skrll .set_rate = imx_ccm_fixed_factor_set_rate, \ 220 1.1 skrll .get_parent = imx_ccm_fixed_factor_get_parent, \ 221 1.1 skrll } 222 1.1 skrll 223 1.1 skrll /* Mux clocks */ 224 1.1 skrll 225 1.1 skrll struct imx_ccm_mux { 226 1.1 skrll bus_size_t reg; 227 1.1 skrll const char **parents; 228 1.1 skrll u_int nparents; 229 1.1 skrll uint32_t sel; 230 1.1 skrll }; 231 1.1 skrll 232 1.1 skrll const char *imx_ccm_mux_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 233 1.1 skrll int imx_ccm_mux_set_parent(struct imx_ccm_softc *, struct imx_ccm_clk *, const char *); 234 1.1 skrll 235 1.1 skrll #define IMX_MUX(_id, _name, _parents, _reg, _sel) \ 236 1.1 skrll IMX_MUX_INDEX(_id, 0, _name, _parents, _reg, _sel) 237 1.1 skrll 238 1.1 skrll #define IMX_MUX_INDEX(_id, _regidx, _name, _parents, _reg, _sel) \ 239 1.1 skrll { \ 240 1.1 skrll .id = (_id), \ 241 1.1 skrll .regidx = (_regidx), \ 242 1.1 skrll .type = IMX_CCM_MUX, \ 243 1.1 skrll .base.name = (_name), \ 244 1.1 skrll .base.flags = CLK_SET_RATE_PARENT, \ 245 1.1 skrll .u.mux.parents = (_parents), \ 246 1.1 skrll .u.mux.nparents = __arraycount(_parents), \ 247 1.1 skrll .u.mux.reg = (_reg), \ 248 1.1 skrll .u.mux.sel = (_sel), \ 249 1.1 skrll .get_parent = imx_ccm_mux_get_parent, \ 250 1.1 skrll .set_parent = imx_ccm_mux_set_parent, \ 251 1.1 skrll } 252 1.1 skrll 253 1.1 skrll /* Divider clocks */ 254 1.1 skrll 255 1.1 skrll struct imx_ccm_div { 256 1.1 skrll bus_size_t reg; 257 1.1 skrll const char *parent; 258 1.1 skrll uint32_t mask; 259 1.1 skrll u_int flags; 260 1.1 skrll #define IMX_DIV_SET_RATE_PARENT __BIT(0) 261 1.1 skrll #define IMX_DIV_ROUND_DOWN __BIT(1) 262 1.1 skrll }; 263 1.1 skrll 264 1.1 skrll u_int imx_ccm_div_get_rate(struct imx_ccm_softc *, struct imx_ccm_clk *); 265 1.1 skrll int imx_ccm_div_set_rate(struct imx_ccm_softc *, struct imx_ccm_clk *, u_int); 266 1.1 skrll const char *imx_ccm_div_get_parent(struct imx_ccm_softc *, struct imx_ccm_clk *); 267 1.1 skrll 268 1.1 skrll #define IMX_DIV(_id, _name, _parent, _reg, _mask, _flags) \ 269 1.1 skrll IMX_DIV_INDEX(_id, 0, _name, _parent, _reg, _mask, _flags) 270 1.1 skrll #define IMX_DIV_INDEX(_id, _regidx, _name, _parent, _reg, _mask, _flags) \ 271 1.1 skrll { \ 272 1.1 skrll .id = (_id), \ 273 1.1 skrll .regidx = (_regidx), \ 274 1.1 skrll .type = IMX_CCM_DIV, \ 275 1.1 skrll .base.name = (_name), \ 276 1.1 skrll .base.flags = 0, \ 277 1.1 skrll .u.div.parent = (_parent), \ 278 1.1 skrll .u.div.reg = (_reg), \ 279 1.1 skrll .u.div.mask = (_mask), \ 280 1.1 skrll .u.div.flags = (_flags), \ 281 1.1 skrll .get_rate = imx_ccm_div_get_rate, \ 282 1.1 skrll .set_rate = imx_ccm_div_set_rate, \ 283 1.1 skrll .get_parent = imx_ccm_div_get_parent, \ 284 1.1 skrll } 285 1.1 skrll 286 1.1 skrll /* 287 1.1 skrll * IMX clock definition 288 1.1 skrll */ 289 1.1 skrll 290 1.1 skrll struct imx_ccm_clk { 291 1.1 skrll struct clk base; 292 1.1 skrll u_int id; 293 1.1 skrll u_int regidx; 294 1.1 skrll enum imx_ccm_clktype type; 295 1.1 skrll union { 296 1.1 skrll struct imx_ccm_gate gate; 297 1.1 skrll struct imx_ccm_composite composite; 298 1.1 skrll struct imx_ccm_pll pll; 299 1.1 skrll struct imx_ccm_fixed fixed; 300 1.1 skrll struct imx_ccm_fixed_factor fixed_factor; 301 1.1 skrll struct imx_ccm_mux mux; 302 1.1 skrll struct imx_ccm_div div; 303 1.1 skrll const char *extclk; 304 1.1 skrll } u; 305 1.1 skrll 306 1.1 skrll int (*enable)(struct imx_ccm_softc *, 307 1.1 skrll struct imx_ccm_clk *, int); 308 1.1 skrll u_int (*get_rate)(struct imx_ccm_softc *, 309 1.1 skrll struct imx_ccm_clk *); 310 1.1 skrll int (*set_rate)(struct imx_ccm_softc *, 311 1.1 skrll struct imx_ccm_clk *, u_int); 312 1.1 skrll u_int (*round_rate)(struct imx_ccm_softc *, 313 1.1 skrll struct imx_ccm_clk *, u_int); 314 1.1 skrll const char * (*get_parent)(struct imx_ccm_softc *, 315 1.1 skrll struct imx_ccm_clk *); 316 1.1 skrll int (*set_parent)(struct imx_ccm_softc *, 317 1.1 skrll struct imx_ccm_clk *, 318 1.1 skrll const char *); 319 1.1 skrll }; 320 1.1 skrll 321 1.1 skrll /* 322 1.1 skrll * Driver state 323 1.1 skrll */ 324 1.1 skrll 325 1.1 skrll struct imx_ccm_softc { 326 1.1 skrll device_t sc_dev; 327 1.1 skrll int sc_phandle; 328 1.1 skrll bus_space_tag_t sc_bst; 329 1.1 skrll bus_space_handle_t sc_bsh[2]; 330 1.1 skrll 331 1.1 skrll bus_addr_t sc_baseaddr; 332 1.1 skrll 333 1.1 skrll struct clk_domain sc_clkdom; 334 1.1 skrll 335 1.1 skrll struct imx_ccm_clk *sc_clks; 336 1.1 skrll u_int sc_nclks; 337 1.1 skrll }; 338 1.1 skrll 339 1.1 skrll int imx_ccm_attach(struct imx_ccm_softc *); 340 1.1 skrll struct imx_ccm_clk *imx_ccm_clock_find(struct imx_ccm_softc *, 341 1.1 skrll const char *); 342 1.1 skrll void imx_ccm_print(struct imx_ccm_softc *); 343 1.1 skrll 344 1.1 skrll extern const struct clk_funcs imx_ccm_clock_funcs; 345 1.1 skrll 346 1.1 skrll #define CCM_READ(sc, idx, reg) \ 347 1.1 skrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg)) 348 1.1 skrll #define CCM_WRITE(sc, idx, reg, val) \ 349 1.1 skrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh[idx], (reg), (val)) 350 1.1 skrll 351 1.1 skrll #endif /* _ARM_IMX_CCM_H */ 352