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/extres/clk/clk.h> 32 #include <dev/extres/clk/clk_div.h> 33 #include <dev/extres/clk/clk_gate.h> 34 #include <dev/extres/clk/clk_fixed.h> 35 #include <dev/extres/clk/clk_link.h> 36 37 #include <arm64/rockchip/clk/rk_clk_armclk.h> 38 #include <arm64/rockchip/clk/rk_clk_composite.h> 39 #include <arm64/rockchip/clk/rk_clk_fract.h> 40 #include <arm64/rockchip/clk/rk_clk_gate.h> 41 #include <arm64/rockchip/clk/rk_clk_mux.h> 42 #include <arm64/rockchip/clk/rk_clk_pll.h> 43 44 /* Macro for defining various types of clocks. */ 45 /* Pure gate */ 46 #define GATE(_idx, _clkname, _pname, _o, _s) \ 47 { \ 48 .id = _idx, \ 49 .name = _clkname, \ 50 .parent_name = _pname, \ 51 .offset = CRU_CLKGATE_CON(_o), \ 52 .shift = _s, \ 53 } 54 55 /* Fixed rate clock. */ 56 #define FRATE(_id, _name, _freq) \ 57 { \ 58 .type = RK_CLK_FIXED, \ 59 .clk.fixed = &(struct clk_fixed_def) { \ 60 .clkdef.id = _id, \ 61 .clkdef.name = _name, \ 62 .clkdef.parent_names = NULL, \ 63 .clkdef.parent_cnt = 0, \ 64 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 65 .freq = _freq, \ 66 }, \ 67 } 68 69 /* Fixed factor multipier/divider. */ 70 #define FFACT(_id, _name, _pname, _mult, _div) \ 71 { \ 72 .type = RK_CLK_FIXED, \ 73 .clk.fixed = &(struct clk_fixed_def) { \ 74 .clkdef.id = _id, \ 75 .clkdef.name = _name, \ 76 .clkdef.parent_names = (const char *[]){_pname}, \ 77 .clkdef.parent_cnt = 1, \ 78 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 79 .mult = _mult, \ 80 .div = _div, \ 81 }, \ 82 } 83 84 /* Linked clock. */ 85 #define LINK(_name) \ 86 { \ 87 .type = RK_CLK_LINK, \ 88 .clk.link = &(struct clk_link_def) { \ 89 .clkdef.id = 0, \ 90 .clkdef.name = _name, \ 91 .clkdef.parent_names = NULL, \ 92 .clkdef.parent_cnt = 0, \ 93 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 94 }, \ 95 } 96 97 /* Complex clock fo ARM cores. */ 98 #define ARMDIV(_id, _name, _pn, _r, _o, _ds, _dw, _ms, _mw, _mp, _ap) \ 99 { \ 100 .type = RK_CLK_ARMCLK, \ 101 .clk.armclk = &(struct rk_clk_armclk_def) { \ 102 .clkdef.id = _id, \ 103 .clkdef.name = _name, \ 104 .clkdef.parent_names = _pn, \ 105 .clkdef.parent_cnt = nitems(_pn), \ 106 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 107 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 108 .mux_shift = _ms, \ 109 .mux_width = _mw, \ 110 .div_shift = _ds, \ 111 .div_width = _dw, \ 112 .main_parent = _mp, \ 113 .alt_parent = _ap, \ 114 .rates = _r, \ 115 .nrates = nitems(_r), \ 116 }, \ 117 } 118 119 /* Fractional rate multipier/divider. */ 120 #define FRACT(_id, _name, _pname, _f, _o) \ 121 { \ 122 .type = RK_CLK_FRACT, \ 123 .clk.fract = &(struct rk_clk_fract_def) { \ 124 .clkdef.id = _id, \ 125 .clkdef.name = _name, \ 126 .clkdef.parent_names = (const char *[]){_pname}, \ 127 .clkdef.parent_cnt = 1, \ 128 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 129 .offset = CRU_CLKSEL_CON(_o), \ 130 .flags = _f, \ 131 }, \ 132 } 133 134 /* Full composite clock. */ 135 #define COMP(_id, _name, _pnames, _f, _o, _ds, _dw, _ms, _mw) \ 136 { \ 137 .type = RK_CLK_COMPOSITE, \ 138 .clk.composite = &(struct rk_clk_composite_def) { \ 139 .clkdef.id = _id, \ 140 .clkdef.name = _name, \ 141 .clkdef.parent_names = _pnames, \ 142 .clkdef.parent_cnt = nitems(_pnames), \ 143 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 144 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 145 .mux_shift = _ms, \ 146 .mux_width = _mw, \ 147 .div_shift = _ds, \ 148 .div_width = _dw, \ 149 .flags = RK_CLK_COMPOSITE_HAVE_MUX | _f, \ 150 }, \ 151 } 152 153 /* Composite clock without mux (divider only). */ 154 #define CDIV(_id, _name, _pname, _f, _o, _ds, _dw) \ 155 { \ 156 .type = RK_CLK_COMPOSITE, \ 157 .clk.composite = &(struct rk_clk_composite_def) { \ 158 .clkdef.id = _id, \ 159 .clkdef.name = _name, \ 160 .clkdef.parent_names = (const char *[]){_pname}, \ 161 .clkdef.parent_cnt = 1, \ 162 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 163 .muxdiv_offset = CRU_CLKSEL_CON(_o), \ 164 .div_shift = _ds, \ 165 .div_width = _dw, \ 166 .flags = _f, \ 167 }, \ 168 } 169 170 /* Complex clock without divider (multiplexer only). */ 171 #define MUXRAW(_id, _name, _pn, _f, _mo, _ms, _mw) \ 172 { \ 173 .type = RK_CLK_MUX, \ 174 .clk.mux = &(struct rk_clk_mux_def) { \ 175 .clkdef.id = _id, \ 176 .clkdef.name = _name, \ 177 .clkdef.parent_names = _pn, \ 178 .clkdef.parent_cnt = nitems(_pn), \ 179 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 180 .offset = _mo, \ 181 .shift = _ms, \ 182 .width = _mw, \ 183 .mux_flags = _f, \ 184 }, \ 185 } 186 187 #define MUX(_id, _name, _pn, _f, _mo, _ms, _mw) \ 188 MUXRAW(_id, _name, _pn, _f, CRU_CLKSEL_CON(_mo), _ms, _mw) 189 190 /* Complex clock without divider (multiplexer only in GRF). */ 191 #define MUXGRF(_id, _name, _pn, _f, _mo, _ms, _mw) \ 192 { \ 193 .type = RK_CLK_MUX, \ 194 .clk.mux = &(struct rk_clk_mux_def) { \ 195 .clkdef.id = _id, \ 196 .clkdef.name = _name, \ 197 .clkdef.parent_names = _pn, \ 198 .clkdef.parent_cnt = nitems(_pn), \ 199 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 200 .offset = _mo, \ 201 .shift = _ms, \ 202 .width = _mw, \ 203 .mux_flags = RK_CLK_MUX_GRF | _f, \ 204 }, \ 205 } 206 207 struct rk_cru_gate { 208 const char *name; 209 const char *parent_name; 210 uint32_t id; 211 uint32_t offset; 212 uint32_t shift; 213 }; 214 215 #define CRU_GATE(idx, clkname, pname, o, s) \ 216 { \ 217 .id = idx, \ 218 .name = clkname, \ 219 .parent_name = pname, \ 220 .offset = o, \ 221 .shift = s, \ 222 }, 223 224 enum rk_clk_type { 225 RK_CLK_UNDEFINED = 0, 226 RK3066_CLK_PLL, 227 RK3328_CLK_PLL, 228 RK3399_CLK_PLL, 229 RK_CLK_COMPOSITE, 230 RK_CLK_FIXED, 231 RK_CLK_FRACT, 232 RK_CLK_MUX, 233 RK_CLK_ARMCLK, 234 RK_CLK_LINK, 235 }; 236 237 struct rk_clk { 238 enum rk_clk_type type; 239 union { 240 struct rk_clk_pll_def *pll; 241 struct rk_clk_composite_def *composite; 242 struct rk_clk_mux_def *mux; 243 struct rk_clk_armclk_def *armclk; 244 struct clk_fixed_def *fixed; 245 struct rk_clk_fract_def *fract; 246 struct clk_link_def *link; 247 } clk; 248 }; 249 250 struct rk_cru_softc { 251 device_t dev; 252 struct resource *res; 253 struct clkdom *clkdom; 254 struct mtx mtx; 255 int type; 256 uint32_t reset_offset; 257 uint32_t reset_num; 258 struct rk_cru_gate *gates; 259 int ngates; 260 struct rk_clk *clks; 261 int nclks; 262 struct rk_clk_armclk_def *armclk; 263 struct rk_clk_armclk_rates *armclk_rates; 264 int narmclk_rates; 265 }; 266 267 DECLARE_CLASS(rk_cru_driver); 268 269 int rk_cru_attach(device_t dev); 270 271 #endif /* __RK_CRU_H__ */ 272