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