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