1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $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 189struct 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 206enum 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 219struct 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 232struct 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 249DECLARE_CLASS(rk_cru_driver); 250 251int rk_cru_attach(device_t dev); 252 253#endif /* __RK_CRU_H__ */ 254