Home | History | Annotate | Line # | Download | only in amlogic
      1 /* $NetBSD: meson_clk.h,v 1.4 2021/01/01 07:21:58 ryo Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2017-2019 Jared McNeill <jmcneill (at) invisible.ca>
      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 
     29 #ifndef _ARM_MESON_CLK_H
     30 #define _ARM_MESON_CLK_H
     31 
     32 #include <dev/clk/clk_backend.h>
     33 #include <dev/fdt/syscon.h>
     34 
     35 struct meson_clk_softc;
     36 struct meson_clk_clk;
     37 struct meson_clk_reset;
     38 
     39 /*
     40  * Resets
     41  */
     42 
     43 struct meson_clk_reset {
     44 	bus_size_t	reg;
     45 	uint32_t	mask;
     46 };
     47 
     48 #define	MESON_CLK_RESET(_id, _reg, _bit)	\
     49 	[_id] = {				\
     50 		.reg = (_reg),			\
     51 		.mask = __BIT(_bit),		\
     52 	}
     53 
     54 /*
     55  * Clocks
     56  */
     57 
     58 enum meson_clk_clktype {
     59 	MESON_CLK_UNKNOWN,
     60 	MESON_CLK_FIXED,
     61 	MESON_CLK_GATE,
     62 	MESON_CLK_PLL,
     63 	MESON_CLK_MPLL,
     64 	MESON_CLK_DIV,
     65 	MESON_CLK_FIXED_FACTOR,
     66 	MESON_CLK_MUX,
     67 };
     68 
     69 /*
     70  * Fixed clocks
     71  */
     72 
     73 struct meson_clk_fixed {
     74 	u_int		rate;
     75 };
     76 
     77 u_int	meson_clk_fixed_get_rate(struct meson_clk_softc *, struct meson_clk_clk *);
     78 
     79 #define	MESON_CLK_FIXED(_id, _name, _rate)			\
     80 	[_id] = {						\
     81 		.type = MESON_CLK_FIXED,			\
     82 		.base.name = (_name),				\
     83 		.base.flags = 0,				\
     84 		.u.fixed.rate = (_rate),			\
     85 		.get_rate = meson_clk_fixed_get_rate,		\
     86 	}
     87 
     88 /*
     89  * Gate clocks
     90  */
     91 
     92 struct meson_clk_gate {
     93 	bus_size_t	reg;
     94 	uint32_t	mask;
     95 	const char	*parent;
     96 	uint32_t	flags;
     97 #define	MESON_CLK_GATE_SET_TO_DISABLE		__BIT(0)
     98 };
     99 
    100 int	meson_clk_gate_enable(struct meson_clk_softc *,
    101 			      struct meson_clk_clk *, int);
    102 const char *meson_clk_gate_get_parent(struct meson_clk_softc *,
    103 				      struct meson_clk_clk *);
    104 
    105 #define	MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, _flags)	\
    106 	[_id] = {						\
    107 		.type = MESON_CLK_GATE,				\
    108 		.base.name = (_name),				\
    109 		.base.flags = CLK_SET_RATE_PARENT,		\
    110 		.u.gate.parent = (_pname),			\
    111 		.u.gate.reg = (_reg),				\
    112 		.u.gate.mask = __BIT(_bit),			\
    113 		.u.gate.flags = (_flags),			\
    114 		.enable = meson_clk_gate_enable,		\
    115 		.get_parent = meson_clk_gate_get_parent,	\
    116 	}
    117 
    118 #define	MESON_CLK_GATE(_id, _name, _pname, _reg, _bit)		\
    119 	MESON_CLK_GATE_FLAGS(_id, _name, _pname, _reg, _bit, 0)
    120 
    121 /*
    122  * Divider clocks
    123  */
    124 
    125 struct meson_clk_div {
    126 	bus_size_t	reg;
    127 	const char	*parent;
    128 	uint32_t	div;
    129 	uint32_t	flags;
    130 #define	MESON_CLK_DIV_POWER_OF_TWO	__BIT(0)
    131 #define	MESON_CLK_DIV_SET_RATE_PARENT	__BIT(1)
    132 #define	MESON_CLK_DIV_CPU_SCALE_TABLE	__BIT(2)
    133 };
    134 
    135 u_int	meson_clk_div_get_rate(struct meson_clk_softc *,
    136 			       struct meson_clk_clk *);
    137 int	meson_clk_div_set_rate(struct meson_clk_softc *,
    138 			       struct meson_clk_clk *, u_int);
    139 const char *meson_clk_div_get_parent(struct meson_clk_softc *,
    140 				     struct meson_clk_clk *);
    141 
    142 #define	MESON_CLK_DIV(_id, _name, _parent, _reg, _div, _flags)	\
    143 	[_id] = {						\
    144 		.type = MESON_CLK_DIV,				\
    145 		.base.name = (_name),				\
    146 		.u.div.reg = (_reg),				\
    147 		.u.div.parent = (_parent),			\
    148 		.u.div.div = (_div),				\
    149 		.u.div.flags = (_flags),			\
    150 		.get_rate = meson_clk_div_get_rate,		\
    151 		.set_rate = meson_clk_div_set_rate,		\
    152 		.get_parent = meson_clk_div_get_parent,		\
    153 	}
    154 
    155 /*
    156  * Fixed-factor clocks
    157  */
    158 
    159 struct meson_clk_fixed_factor {
    160 	const char	*parent;
    161 	u_int		div;
    162 	u_int		mult;
    163 };
    164 
    165 u_int	meson_clk_fixed_factor_get_rate(struct meson_clk_softc *,
    166 					struct meson_clk_clk *);
    167 int	meson_clk_fixed_factor_set_rate(struct meson_clk_softc *,
    168 					struct meson_clk_clk *, u_int);
    169 const char *meson_clk_fixed_factor_get_parent(struct meson_clk_softc *,
    170 					      struct meson_clk_clk *);
    171 
    172 #define	MESON_CLK_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
    173 	[_id] = {							\
    174 		.type = MESON_CLK_FIXED_FACTOR,				\
    175 		.base.name = (_name),					\
    176 		.u.fixed_factor.parent = (_parent),			\
    177 		.u.fixed_factor.div = (_div),				\
    178 		.u.fixed_factor.mult = (_mult),				\
    179 		.get_rate = meson_clk_fixed_factor_get_rate,		\
    180 		.get_parent = meson_clk_fixed_factor_get_parent,	\
    181 		.set_rate = meson_clk_fixed_factor_set_rate,		\
    182 	}
    183 
    184 /*
    185  * Mux clocks
    186  */
    187 
    188 struct meson_clk_mux {
    189 	bus_size_t	reg;
    190 	const char	**parents;
    191 	u_int		nparents;
    192 	uint32_t	sel;
    193 	uint32_t	flags;
    194 };
    195 
    196 const char *meson_clk_mux_get_parent(struct meson_clk_softc *,
    197 			       struct meson_clk_clk *);
    198 
    199 #define	MESON_CLK_MUX_RATE(_id, _name, _parents, _reg, _sel,		\
    200 			   _getratefn, _setratefn, _flags)		\
    201 	[_id] = {							\
    202 		.type = MESON_CLK_MUX,					\
    203 		.base.name = (_name),					\
    204 		.base.flags = 0,					\
    205 		.u.mux.parents = (_parents),				\
    206 		.u.mux.nparents = __arraycount(_parents),		\
    207 		.u.mux.reg = (_reg),					\
    208 		.u.mux.sel = (_sel),					\
    209 		.u.mux.flags = (_flags),				\
    210 		.get_rate = _getratefn,					\
    211 		.set_rate = _setratefn,					\
    212 		.get_parent = meson_clk_mux_get_parent,			\
    213 	}
    214 
    215 #define	MESON_CLK_MUX(_id, _name, _parents, _reg, _sel, _flags)		\
    216 	[_id] = {							\
    217 		.type = MESON_CLK_MUX,					\
    218 		.base.name = (_name),					\
    219 		.base.flags = CLK_SET_RATE_PARENT,			\
    220 		.u.mux.parents = (_parents),				\
    221 		.u.mux.nparents = __arraycount(_parents),		\
    222 		.u.mux.reg = (_reg),					\
    223 		.u.mux.sel = (_sel),					\
    224 		.u.mux.flags = (_flags),				\
    225 		.get_parent = meson_clk_mux_get_parent,			\
    226 	}
    227 
    228 /*
    229  * PLL clocks
    230  */
    231 
    232 struct meson_clk_pll_reg {
    233 	bus_size_t	reg;
    234 	uint32_t	mask;
    235 };
    236 
    237 #define	MESON_CLK_PLL_REG(_reg, _mask)					\
    238 	{ .reg = (_reg), .mask = (_mask) }
    239 #define	MESON_CLK_PLL_REG_INVALID	MESON_CLK_PLL_REG(0,0)
    240 
    241 struct meson_clk_pll {
    242 	struct meson_clk_pll_reg	enable;
    243 	struct meson_clk_pll_reg	m;
    244 	struct meson_clk_pll_reg	n;
    245 	struct meson_clk_pll_reg	frac;
    246 	struct meson_clk_pll_reg	l;
    247 	struct meson_clk_pll_reg	reset;
    248 	const char			*parent;
    249 	uint32_t			flags;
    250 };
    251 
    252 u_int	meson_clk_pll_get_rate(struct meson_clk_softc *,
    253 			       struct meson_clk_clk *);
    254 int	meson_clk_pll_set_rate(struct meson_clk_softc *,
    255 			       struct meson_clk_clk *, u_int new_rate);
    256 const char *meson_clk_pll_get_parent(struct meson_clk_softc *,
    257 				     struct meson_clk_clk *);
    258 int	meson_clk_pll_wait_lock(struct meson_clk_softc *sc,
    259 				struct meson_clk_pll *pll);
    260 
    261 
    262 #define	MESON_CLK_PLL_RATE(_id, _name, _parent, _enable, _m, _n, _frac, _l,	\
    263 		      _reset, _setratefn, _flags)			\
    264 	[_id] = {							\
    265 		.type = MESON_CLK_PLL,					\
    266 		.base.name = (_name),					\
    267 		.u.pll.parent = (_parent),				\
    268 		.u.pll.enable = _enable,				\
    269 		.u.pll.m = _m,						\
    270 		.u.pll.n = _n,						\
    271 		.u.pll.frac = _frac,					\
    272 		.u.pll.l = _l,						\
    273 		.u.pll.reset = _reset,					\
    274 		.u.pll.flags = (_flags),				\
    275 		.set_rate = (_setratefn),				\
    276 		.get_rate = meson_clk_pll_get_rate,			\
    277 		.get_parent = meson_clk_pll_get_parent,			\
    278 	}
    279 
    280 #define	MESON_CLK_PLL(_id, _name, _parent, _enable, _m, _n, _frac, _l,	\
    281 		      _reset, _flags)					\
    282 	[_id] = {							\
    283 		.type = MESON_CLK_PLL,					\
    284 		.base.name = (_name),					\
    285 		.u.pll.parent = (_parent),				\
    286 		.u.pll.enable = _enable,				\
    287 		.u.pll.m = _m,						\
    288 		.u.pll.n = _n,						\
    289 		.u.pll.frac = _frac,					\
    290 		.u.pll.l = _l,						\
    291 		.u.pll.reset = _reset,					\
    292 		.u.pll.flags = (_flags),				\
    293 		.get_rate = meson_clk_pll_get_rate,			\
    294 		.get_parent = meson_clk_pll_get_parent,			\
    295 	}
    296 
    297 /*
    298  * MPLL clocks
    299  */
    300 
    301 struct meson_clk_mpll {
    302 	struct meson_clk_pll_reg	sdm;
    303 	struct meson_clk_pll_reg	sdm_enable;
    304 	struct meson_clk_pll_reg	n2;
    305 	struct meson_clk_pll_reg	ssen;
    306 	const char			*parent;
    307 	uint32_t			flags;
    308 };
    309 
    310 u_int	meson_clk_mpll_get_rate(struct meson_clk_softc *,
    311 				struct meson_clk_clk *);
    312 const char *meson_clk_mpll_get_parent(struct meson_clk_softc *,
    313 				      struct meson_clk_clk *);
    314 
    315 #define	MESON_CLK_MPLL(_id, _name, _parent, _sdm, _sdm_enable, _n2,	\
    316 		       _ssen, _flags)					\
    317 	[_id] = {							\
    318 		.type = MESON_CLK_MPLL,					\
    319 		.base.name = (_name),					\
    320 		.u.mpll.parent = (_parent),				\
    321 		.u.mpll.sdm = _sdm,					\
    322 		.u.mpll.sdm_enable = _sdm_enable,			\
    323 		.u.mpll.n2 = _n2,					\
    324 		.u.mpll.ssen = _ssen,					\
    325 		.u.mpll.flags = (_flags),				\
    326 		.get_rate = meson_clk_mpll_get_rate,			\
    327 		.get_parent = meson_clk_mpll_get_parent,		\
    328 	}
    329 
    330 
    331 
    332 struct meson_clk_clk {
    333 	struct clk	base;
    334 	enum meson_clk_clktype type;
    335 	union {
    336 		struct meson_clk_fixed fixed;
    337 		struct meson_clk_gate gate;
    338 		struct meson_clk_div div;
    339 		struct meson_clk_fixed_factor fixed_factor;
    340 		struct meson_clk_mux mux;
    341 		struct meson_clk_pll pll;
    342 		struct meson_clk_mpll mpll;
    343 	} u;
    344 
    345 	int		(*enable)(struct meson_clk_softc *,
    346 				  struct meson_clk_clk *, int);
    347 	u_int		(*get_rate)(struct meson_clk_softc *,
    348 				    struct meson_clk_clk *);
    349 	int		(*set_rate)(struct meson_clk_softc *,
    350 				    struct meson_clk_clk *, u_int);
    351 	u_int		(*round_rate)(struct meson_clk_softc *,
    352 				    struct meson_clk_clk *, u_int);
    353 	const char *	(*get_parent)(struct meson_clk_softc *,
    354 				      struct meson_clk_clk *);
    355 	int		(*set_parent)(struct meson_clk_softc *,
    356 				      struct meson_clk_clk *,
    357 				      const char *);
    358 };
    359 
    360 struct meson_clk_softc {
    361 	device_t		sc_dev;
    362 	int			sc_phandle;
    363 
    364 	bus_space_tag_t		sc_bst;
    365 	bus_space_handle_t	sc_bsh;
    366 
    367 	struct syscon		*sc_syscon;
    368 
    369 	struct clk_domain	sc_clkdom;
    370 
    371 	struct meson_clk_reset *sc_resets;
    372 	u_int			sc_nresets;
    373 
    374 	struct meson_clk_clk	*sc_clks;
    375 	u_int			sc_nclks;
    376 };
    377 
    378 void	meson_clk_attach(struct meson_clk_softc *);
    379 struct meson_clk_clk *meson_clk_clock_find(struct meson_clk_softc *,
    380 					   const char *);
    381 void	meson_clk_print(struct meson_clk_softc *);
    382 
    383 void	meson_clk_lock(struct meson_clk_softc *);
    384 void	meson_clk_unlock(struct meson_clk_softc *);
    385 uint32_t meson_clk_read(struct meson_clk_softc *, bus_size_t);
    386 void	meson_clk_write(struct meson_clk_softc *, bus_size_t, uint32_t);
    387 
    388 #define	CLK_LOCK	meson_clk_lock
    389 #define	CLK_UNLOCK	meson_clk_unlock
    390 #define	CLK_READ	meson_clk_read
    391 #define	CLK_WRITE	meson_clk_write
    392 #define CLK_WRITE_BITS(sc, reg, mask, val)			\
    393 	do {							\
    394 		uint32_t _cwb_tmp_ = CLK_READ((sc), (reg));	\
    395 		_cwb_tmp_ &= ~(mask);				\
    396 		_cwb_tmp_ |= __SHIFTIN((val), (mask));		\
    397 		CLK_WRITE((sc), (reg), _cwb_tmp_);		\
    398 	} while (0 /*CONSTCOND*/)
    399 
    400 #endif /* _ARM_MESON_CLK_H */
    401