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