1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #ifndef __RK_CRU_H__ 29 #define __RK_CRU_H__ 30 31 #include <dev/clk/clk.h> 32 #include <dev/clk/clk_div.h> 33 #include <dev/clk/clk_gate.h> 34 #include <dev/clk/clk_fixed.h> 35 #include <dev/clk/clk_link.h> 36 37 #include <dev/clk/rockchip/rk_clk_armclk.h> 38 #include <dev/clk/rockchip/rk_clk_composite.h> 39 #include <dev/clk/rockchip/rk_clk_fract.h> 40 #include <dev/clk/rockchip/rk_clk_gate.h> 41 #include <dev/clk/rockchip/rk_clk_mux.h> 42 #include <dev/clk/rockchip/rk_clk_pll.h> 43 44 /* Macro for defining various types of clocks. */ 45 46 /* Parent list */ 47 #define PLIST(_name) static const char *_name[] 48 49 /* Pure gate */ 50 #define GATE(_idx, _clkname, _pname, _o, _s) \ 51 { \ 52 .id = _idx, \ 53 .name = _clkname, \ 54 .parent_name = _pname, \ 55 .offset = CRU_CLKGATE_CON(_o), \ 56 .shift = _s, \ 57 } 58 59 /* Fixed rate clock. */ 60 #define FRATE(_id, _name, _freq) \ 61 { \ 62 .type = RK_CLK_FIXED, \ 63 .clk.fixed = &(struct clk_fixed_def) { \ 64 .clkdef.id = _id, \ 65 .clkdef.name = _name, \ 66 .clkdef.parent_names = NULL, \ 67 .clkdef.parent_cnt = 0, \ 68 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 69 .freq = _freq, \ 70 }, \ 71 } 72 73 /* Fixed factor multipier/divider. */ 74 #define FFACT(_id, _name, _pname, _mult, _div) \ 75 { \ 76 .type = RK_CLK_FIXED, \ 77 .clk.fixed = &(struct clk_fixed_def) { \ 78 .clkdef.id = _id, \ 79 .clkdef.name = _name, \ 80 .clkdef.parent_names = (const char *[]){_pname}, \ 81 .clkdef.parent_cnt = 1, \ 82 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 83 .mult = _mult, \ 84 .div = _div, \ 85 }, \ 86 } 87 88 /* Linked clock. */ 89 #define LINK(_name) \ 90 { \ 91 .type = RK_CLK_LINK, \ 92 .clk.link = &(struct clk_link_def) { \ 93 .clkdef.id = 0, \ 94 .clkdef.name = _name, \ 95 .clkdef.parent_names = NULL, \ 96 .clkdef.parent_cnt = 0, \ 97 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 98 }, \ 99 } 100 101 /* Complex clock fo ARM cores. */ 102 #define ARMDIV(_id, _name, _pn, _r, _o, _ds, _dw, _ms, _mw, _mp, _ap) \ 103 { \ 104 .type = RK_CLK_ARMCLK, \ 105 .clk.armclk = &(struct rk_clk_armclk_def) { \ 106 .clkdef.id = _id, \ 107 .clkdef.name = _name, \ 108 .clkdef.parent_names = _pn, \ 109 .clkdef.parent_cnt = nitems(_pn), \ 110 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 111 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 112 .mux_shift = _ms, \ 113 .mux_width = _mw, \ 114 .div_shift = _ds, \ 115 .div_width = _dw, \ 116 .main_parent = _mp, \ 117 .alt_parent = _ap, \ 118 .rates = _r, \ 119 .nrates = nitems(_r), \ 120 }, \ 121 } 122 123 /* Fractional rate multipier/divider. */ 124 #define FRACT(_id, _name, _pname, _f, _o) \ 125 { \ 126 .type = RK_CLK_FRACT, \ 127 .clk.fract = &(struct rk_clk_fract_def) { \ 128 .clkdef.id = _id, \ 129 .clkdef.name = _name, \ 130 .clkdef.parent_names = (const char *[]){_pname}, \ 131 .clkdef.parent_cnt = 1, \ 132 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 133 .offset = CRU_CLKSEL_CON(_o), \ 134 .flags = _f, \ 135 }, \ 136 } 137 138 /* Full composite clock. */ 139 #define COMP(_id, _name, _pnames, _f, _o, _ds, _dw, _ms, _mw) \ 140 { \ 141 .type = RK_CLK_COMPOSITE, \ 142 .clk.composite = &(struct rk_clk_composite_def) { \ 143 .clkdef.id = _id, \ 144 .clkdef.name = _name, \ 145 .clkdef.parent_names = _pnames, \ 146 .clkdef.parent_cnt = nitems(_pnames), \ 147 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 148 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 149 .mux_shift = _ms, \ 150 .mux_width = _mw, \ 151 .div_shift = _ds, \ 152 .div_width = _dw, \ 153 .flags = RK_CLK_COMPOSITE_HAVE_MUX | _f, \ 154 }, \ 155 } 156 157 /* Composite clock without mux (divider only). */ 158 #define CDIV(_id, _name, _pname, _f, _o, _ds, _dw) \ 159 { \ 160 .type = RK_CLK_COMPOSITE, \ 161 .clk.composite = &(struct rk_clk_composite_def) { \ 162 .clkdef.id = _id, \ 163 .clkdef.name = _name, \ 164 .clkdef.parent_names = (const char *[]){_pname}, \ 165 .clkdef.parent_cnt = 1, \ 166 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 167 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 168 .div_shift = _ds, \ 169 .div_width = _dw, \ 170 .flags = _f, \ 171 }, \ 172 } 173 174 /* Complex clock without divider (multiplexer only). */ 175 #define MUXRAW(_id, _name, _pn, _f, _mo, _ms, _mw) \ 176 { \ 177 .type = RK_CLK_MUX, \ 178 .clk.mux = &(struct rk_clk_mux_def) { \ 179 .clkdef.id = _id, \ 180 .clkdef.name = _name, \ 181 .clkdef.parent_names = _pn, \ 182 .clkdef.parent_cnt = nitems(_pn), \ 183 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 184 .offset = _mo, \ 185 .shift = _ms, \ 186 .width = _mw, \ 187 .mux_flags = _f, \ 188 }, \ 189 } 190 191 #define MUX(_id, _name, _pn, _f, _mo, _ms, _mw) \ 192 MUXRAW(_id, _name, _pn, _f, CRU_CLKSEL_CON(_mo), _ms, _mw) 193 194 /* Complex clock without divider (multiplexer only in GRF). */ 195 #define MUXGRF(_id, _name, _pn, _f, _mo, _ms, _mw) \ 196 { \ 197 .type = RK_CLK_MUX, \ 198 .clk.mux = &(struct rk_clk_mux_def) { \ 199 .clkdef.id = _id, \ 200 .clkdef.name = _name, \ 201 .clkdef.parent_names = _pn, \ 202 .clkdef.parent_cnt = nitems(_pn), \ 203 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 204 .offset = _mo, \ 205 .shift = _ms, \ 206 .width = _mw, \ 207 .mux_flags = RK_CLK_MUX_GRF | _f, \ 208 }, \ 209 } 210 211 struct rk_cru_gate { 212 const char *name; 213 const char *parent_name; 214 uint32_t id; 215 uint32_t offset; 216 uint32_t shift; 217 }; 218 219 enum rk_clk_type { 220 RK_CLK_UNDEFINED = 0, 221 RK3066_CLK_PLL, 222 RK3328_CLK_PLL, 223 RK3399_CLK_PLL, 224 RK_CLK_COMPOSITE, 225 RK_CLK_FIXED, 226 RK_CLK_FRACT, 227 RK_CLK_MUX, 228 RK_CLK_ARMCLK, 229 RK_CLK_LINK, 230 }; 231 232 struct rk_clk { 233 enum rk_clk_type type; 234 union { 235 struct rk_clk_pll_def *pll; 236 struct rk_clk_composite_def *composite; 237 struct rk_clk_mux_def *mux; 238 struct rk_clk_armclk_def *armclk; 239 struct clk_fixed_def *fixed; 240 struct rk_clk_fract_def *fract; 241 struct clk_link_def *link; 242 } clk; 243 }; 244 245 struct rk_cru_softc { 246 device_t dev; 247 struct resource *res; 248 struct clkdom *clkdom; 249 struct mtx mtx; 250 int type; 251 uint32_t reset_offset; 252 uint32_t reset_num; 253 struct rk_cru_gate *gates; 254 int ngates; 255 struct rk_clk *clks; 256 int nclks; 257 struct rk_clk_armclk_def *armclk; 258 struct rk_clk_armclk_rates *armclk_rates; 259 int narmclk_rates; 260 }; 261 262 DECLARE_CLASS(rk_cru_driver); 263 264 int rk_cru_attach(device_t dev); 265 266 #endif /* __RK_CRU_H__ */ 267