Home | History | Annotate | Line # | Download | only in sunxi
sunxi_ccu.h revision 1.19
      1 /* $NetBSD: sunxi_ccu.h,v 1.19 2019/01/02 17:29:58 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2017 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_SUNXI_CCU_H
     30 #define _ARM_SUNXI_CCU_H
     31 
     32 #include <dev/clk/clk_backend.h>
     33 
     34 struct sunxi_ccu_softc;
     35 struct sunxi_ccu_clk;
     36 struct sunxi_ccu_reset;
     37 
     38 /*
     39  * Resets
     40  */
     41 
     42 struct sunxi_ccu_reset {
     43 	bus_size_t	reg;
     44 	uint32_t	mask;
     45 };
     46 
     47 #define	SUNXI_CCU_RESET(_id, _reg, _bit)	\
     48 	[_id] = {				\
     49 		.reg = (_reg),			\
     50 		.mask = __BIT(_bit),		\
     51 	}
     52 
     53 /*
     54  * Clocks
     55  */
     56 
     57 enum sunxi_ccu_clktype {
     58 	SUNXI_CCU_UNKNOWN,
     59 	SUNXI_CCU_GATE,
     60 	SUNXI_CCU_NM,
     61 	SUNXI_CCU_NKMP,
     62 	SUNXI_CCU_PREDIV,
     63 	SUNXI_CCU_DIV,
     64 	SUNXI_CCU_PHASE,
     65 	SUNXI_CCU_FIXED_FACTOR,
     66 	SUNXI_CCU_FRACTIONAL,
     67 };
     68 
     69 struct sunxi_ccu_gate {
     70 	bus_size_t	reg;
     71 	uint32_t	mask;
     72 	const char	*parent;
     73 };
     74 
     75 int	sunxi_ccu_gate_enable(struct sunxi_ccu_softc *,
     76 			      struct sunxi_ccu_clk *, int);
     77 const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *,
     78 				      struct sunxi_ccu_clk *);
     79 
     80 #define	SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit)		\
     81 	[_id] = {						\
     82 		.type = SUNXI_CCU_GATE,				\
     83 		.base.name = (_name),				\
     84 		.base.flags = CLK_SET_RATE_PARENT,		\
     85 		.u.gate.parent = (_pname),			\
     86 		.u.gate.reg = (_reg),				\
     87 		.u.gate.mask = __BIT(_bit),			\
     88 		.enable = sunxi_ccu_gate_enable,		\
     89 		.get_parent = sunxi_ccu_gate_get_parent,	\
     90 	}
     91 
     92 struct sunxi_ccu_nkmp_tbl {
     93 	u_int		rate;
     94 	uint32_t	n;
     95 	uint32_t	k;
     96 	uint32_t	m;
     97 	uint32_t	p;
     98 };
     99 
    100 struct sunxi_ccu_nkmp {
    101 	bus_size_t	reg;
    102 	const char	*parent;
    103 	uint32_t	n;
    104 	uint32_t	k;
    105 	uint32_t	m;
    106 	uint32_t	p;
    107 	uint32_t	lock;
    108 	uint32_t	enable;
    109 	uint32_t	flags;
    110 	const struct sunxi_ccu_nkmp_tbl *table;
    111 #define	SUNXI_CCU_NKMP_DIVIDE_BY_TWO		__BIT(0)
    112 #define	SUNXI_CCU_NKMP_FACTOR_N_EXACT		__BIT(1)
    113 #define	SUNXI_CCU_NKMP_SCALE_CLOCK		__BIT(2)
    114 #define	SUNXI_CCU_NKMP_FACTOR_P_POW2		__BIT(3)
    115 #define	SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE	__BIT(4)
    116 #define	SUNXI_CCU_NKMP_FACTOR_P_X4		__BIT(5)
    117 };
    118 
    119 int	sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *,
    120 			      struct sunxi_ccu_clk *, int);
    121 u_int	sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *,
    122 				struct sunxi_ccu_clk *);
    123 int	sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *,
    124 				struct sunxi_ccu_clk *, u_int);
    125 const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *,
    126 				      struct sunxi_ccu_clk *);
    127 
    128 #define	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
    129 		       _p, _enable, _lock, _tbl, _flags)	\
    130 	[_id] = {						\
    131 		.type = SUNXI_CCU_NKMP,				\
    132 		.base.name = (_name),				\
    133 		.u.nkmp.reg = (_reg),				\
    134 		.u.nkmp.parent = (_parent),			\
    135 		.u.nkmp.n = (_n),				\
    136 		.u.nkmp.k = (_k),				\
    137 		.u.nkmp.m = (_m),				\
    138 		.u.nkmp.p = (_p),				\
    139 		.u.nkmp.enable = (_enable),			\
    140 		.u.nkmp.flags = (_flags),			\
    141 		.u.nkmp.lock = (_lock),				\
    142 		.u.nkmp.table = (_tbl),				\
    143 		.enable = sunxi_ccu_nkmp_enable,		\
    144 		.get_rate = sunxi_ccu_nkmp_get_rate,		\
    145 		.set_rate = sunxi_ccu_nkmp_set_rate,		\
    146 		.get_parent = sunxi_ccu_nkmp_get_parent,	\
    147 	}
    148 
    149 #define	SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m,	\
    150 		       _p, _enable, _flags)			\
    151 	SUNXI_CCU_NKMP_TABLE(_id, _name, _parent, _reg, _n, _k, _m, \
    152 			     _p, _enable, 0, NULL, _flags)
    153 
    154 
    155 struct sunxi_ccu_nm {
    156 	bus_size_t	reg;
    157 	const char	**parents;
    158 	u_int		nparents;
    159 	uint32_t	n;
    160 	uint32_t	m;
    161 	uint32_t	sel;
    162 	uint32_t	enable;
    163 	uint32_t	flags;
    164 #define	SUNXI_CCU_NM_POWER_OF_TWO	__BIT(0)
    165 #define	SUNXI_CCU_NM_ROUND_DOWN		__BIT(1)
    166 #define	SUNXI_CCU_NM_DIVIDE_BY_TWO	__BIT(2)
    167 };
    168 
    169 int	sunxi_ccu_nm_enable(struct sunxi_ccu_softc *,
    170 			    struct sunxi_ccu_clk *, int);
    171 u_int	sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *,
    172 			      struct sunxi_ccu_clk *);
    173 int	sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *,
    174 			      struct sunxi_ccu_clk *, u_int);
    175 int	sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *,
    176 				struct sunxi_ccu_clk *,
    177 				const char *);
    178 const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *,
    179 				    struct sunxi_ccu_clk *);
    180 
    181 #define	SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel,	\
    182 		     _enable, _flags)				\
    183 	[_id] = {						\
    184 		.type = SUNXI_CCU_NM,				\
    185 		.base.name = (_name),				\
    186 		.u.nm.reg = (_reg),				\
    187 		.u.nm.parents = (_parents),			\
    188 		.u.nm.nparents = __arraycount(_parents),	\
    189 		.u.nm.n = (_n),					\
    190 		.u.nm.m = (_m),					\
    191 		.u.nm.sel = (_sel),				\
    192 		.u.nm.enable = (_enable),			\
    193 		.u.nm.flags = (_flags),				\
    194 		.enable = sunxi_ccu_nm_enable,			\
    195 		.get_rate = sunxi_ccu_nm_get_rate,		\
    196 		.set_rate = sunxi_ccu_nm_set_rate,		\
    197 		.set_parent = sunxi_ccu_nm_set_parent,		\
    198 		.get_parent = sunxi_ccu_nm_get_parent,		\
    199 	}
    200 
    201 struct sunxi_ccu_div {
    202 	bus_size_t	reg;
    203 	const char	**parents;
    204 	u_int		nparents;
    205 	uint32_t	div;
    206 	uint32_t	sel;
    207 	uint32_t	enable;
    208 	uint32_t	flags;
    209 #define	SUNXI_CCU_DIV_POWER_OF_TWO	__BIT(0)
    210 #define	SUNXI_CCU_DIV_ZERO_IS_ONE	__BIT(1)
    211 #define	SUNXI_CCU_DIV_TIMES_TWO		__BIT(2)
    212 #define	SUNXI_CCU_DIV_SET_RATE_PARENT	__BIT(3)
    213 };
    214 
    215 int	sunxi_ccu_div_enable(struct sunxi_ccu_softc *,
    216 			     struct sunxi_ccu_clk *, int);
    217 u_int	sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
    218 			       struct sunxi_ccu_clk *);
    219 int	sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
    220 			       struct sunxi_ccu_clk *, u_int);
    221 int	sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *,
    222 			         struct sunxi_ccu_clk *,
    223 			         const char *);
    224 const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *,
    225 				     struct sunxi_ccu_clk *);
    226 
    227 #define	SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div,		\
    228 		      _sel, _flags)				\
    229 	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
    230 			   _sel, 0, _flags)
    231 
    232 #define	SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div,	\
    233 		      _sel, _enable, _flags)			\
    234 	[_id] = {						\
    235 		.type = SUNXI_CCU_DIV,				\
    236 		.base.name = (_name),				\
    237 		.u.div.reg = (_reg),				\
    238 		.u.div.parents = (_parents),			\
    239 		.u.div.nparents = __arraycount(_parents),	\
    240 		.u.div.div = (_div),				\
    241 		.u.div.sel = (_sel),				\
    242 		.u.div.enable = (_enable),			\
    243 		.u.div.flags = (_flags),			\
    244 		.enable = sunxi_ccu_div_enable,			\
    245 		.get_rate = sunxi_ccu_div_get_rate,		\
    246 		.set_rate = sunxi_ccu_div_set_rate,		\
    247 		.set_parent = sunxi_ccu_div_set_parent,		\
    248 		.get_parent = sunxi_ccu_div_get_parent,		\
    249 	}
    250 
    251 /* special case of the div model for display clocks */
    252 int sunxi_ccu_lcdxch0_set_rate(struct sunxi_ccu_softc *,
    253     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
    254     struct sunxi_ccu_clk *, u_int);
    255 u_int sunxi_ccu_lcdxch0_round_rate(struct sunxi_ccu_softc *,
    256     struct sunxi_ccu_clk *, struct sunxi_ccu_clk *,
    257     struct sunxi_ccu_clk *, u_int);
    258 
    259 int sunxi_ccu_lcdxch1_set_rate(struct sunxi_ccu_softc *sc,
    260     struct sunxi_ccu_clk *clk, struct sunxi_ccu_clk *pclk,
    261     struct sunxi_ccu_clk *pclk_x2, u_int);
    262 
    263 struct sunxi_ccu_prediv {
    264 	bus_size_t	reg;
    265 	const char	**parents;
    266 	u_int		nparents;
    267 	uint32_t	prediv;
    268 	uint32_t	prediv_sel;
    269 	uint32_t	prediv_fixed;
    270 	uint32_t	div;
    271 	uint32_t	sel;
    272 	uint32_t	flags;
    273 #define	SUNXI_CCU_PREDIV_POWER_OF_TWO	__BIT(0)
    274 #define	SUNXI_CCU_PREDIV_DIVIDE_BY_TWO	__BIT(1)
    275 };
    276 
    277 u_int	sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *,
    278 				  struct sunxi_ccu_clk *);
    279 int	sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *,
    280 				  struct sunxi_ccu_clk *, u_int);
    281 int	sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *,
    282 				    struct sunxi_ccu_clk *,
    283 				    const char *);
    284 const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *,
    285 					struct sunxi_ccu_clk *);
    286 
    287 #define	SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv,	\
    288 		     _prediv_sel, _div, _sel, _flags)		\
    289 	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
    290 		     _prediv_sel, 0, _div, _sel, _flags)
    291 
    292 #define	SUNXI_CCU_PREDIV_FIXED(_id, _name, _parents, _reg, _prediv, \
    293 		     _prediv_sel, _prediv_fixed, _div, _sel, _flags) \
    294 	[_id] = {						\
    295 		.type = SUNXI_CCU_PREDIV,			\
    296 		.base.name = (_name),				\
    297 		.u.prediv.reg = (_reg),				\
    298 		.u.prediv.parents = (_parents),			\
    299 		.u.prediv.nparents = __arraycount(_parents),	\
    300 		.u.prediv.prediv = (_prediv),			\
    301 		.u.prediv.prediv_sel = (_prediv_sel),		\
    302 		.u.prediv.prediv_fixed = (_prediv_fixed),	\
    303 		.u.prediv.div = (_div),				\
    304 		.u.prediv.sel = (_sel),				\
    305 		.u.prediv.flags = (_flags),			\
    306 		.get_rate = sunxi_ccu_prediv_get_rate,		\
    307 		.set_rate = sunxi_ccu_prediv_set_rate,		\
    308 		.set_parent = sunxi_ccu_prediv_set_parent,	\
    309 		.get_parent = sunxi_ccu_prediv_get_parent,	\
    310 	}
    311 
    312 struct sunxi_ccu_phase {
    313 	bus_size_t	reg;
    314 	const char	*parent;
    315 	uint32_t	mask;
    316 };
    317 
    318 u_int	sunxi_ccu_phase_get_rate(struct sunxi_ccu_softc *,
    319 				 struct sunxi_ccu_clk *);
    320 int	sunxi_ccu_phase_set_rate(struct sunxi_ccu_softc *,
    321 				 struct sunxi_ccu_clk *, u_int);
    322 const char *sunxi_ccu_phase_get_parent(struct sunxi_ccu_softc *,
    323 				       struct sunxi_ccu_clk *);
    324 
    325 #define	SUNXI_CCU_PHASE(_id, _name, _parent, _reg, _mask)	\
    326 	[_id] = {						\
    327 		.type = SUNXI_CCU_PHASE,			\
    328 		.base.name = (_name),				\
    329 		.u.phase.reg = (_reg),				\
    330 		.u.phase.parent = (_parent),			\
    331 		.u.phase.mask = (_mask),			\
    332 		.get_rate = sunxi_ccu_phase_get_rate,		\
    333 		.set_rate = sunxi_ccu_phase_set_rate,		\
    334 		.get_parent = sunxi_ccu_phase_get_parent,	\
    335 	}
    336 
    337 struct sunxi_ccu_fixed_factor {
    338 	const char	*parent;
    339 	u_int		div;
    340 	u_int		mult;
    341 };
    342 
    343 u_int	sunxi_ccu_fixed_factor_get_rate(struct sunxi_ccu_softc *,
    344 					struct sunxi_ccu_clk *);
    345 int	sunxi_ccu_fixed_factor_set_rate(struct sunxi_ccu_softc *,
    346 					struct sunxi_ccu_clk *, u_int);
    347 const char *sunxi_ccu_fixed_factor_get_parent(struct sunxi_ccu_softc *,
    348 					      struct sunxi_ccu_clk *);
    349 
    350 #define	SUNXI_CCU_FIXED_FACTOR(_id, _name, _parent, _div, _mult)	\
    351 	[_id] = {							\
    352 		.type = SUNXI_CCU_FIXED_FACTOR,				\
    353 		.base.name = (_name),					\
    354 		.u.fixed_factor.parent = (_parent),			\
    355 		.u.fixed_factor.div = (_div),				\
    356 		.u.fixed_factor.mult = (_mult),				\
    357 		.get_rate = sunxi_ccu_fixed_factor_get_rate,		\
    358 		.get_parent = sunxi_ccu_fixed_factor_get_parent,	\
    359 		.set_rate = sunxi_ccu_fixed_factor_set_rate,		\
    360 	}
    361 
    362 struct sunxi_ccu_fractional {
    363 	bus_size_t	reg;
    364 	const char	*parent;
    365 	uint32_t	m;
    366 	uint32_t	m_min;
    367 	uint32_t	m_max;
    368 	uint32_t	div_en;
    369 	uint32_t	frac_sel;
    370 	uint32_t	frac[2];
    371 	uint32_t	prediv;
    372 	uint32_t	enable;
    373 };
    374 
    375 int	sunxi_ccu_fractional_enable(struct sunxi_ccu_softc *,
    376 			    struct sunxi_ccu_clk *, int);
    377 u_int	sunxi_ccu_fractional_get_rate(struct sunxi_ccu_softc *,
    378 			      struct sunxi_ccu_clk *);
    379 int	sunxi_ccu_fractional_set_rate(struct sunxi_ccu_softc *,
    380 			      struct sunxi_ccu_clk *, u_int);
    381 u_int	sunxi_ccu_fractional_round_rate(struct sunxi_ccu_softc *,
    382 			      struct sunxi_ccu_clk *, u_int);
    383 const char *sunxi_ccu_fractional_get_parent(struct sunxi_ccu_softc *,
    384 				    struct sunxi_ccu_clk *);
    385 
    386 #define	SUNXI_CCU_FRACTIONAL(_id, _name, _parent, _reg, _m, _m_min, _m_max, \
    387 		     _div_en, _frac_sel, _frac0, _frac1, _prediv, _enable) \
    388 	[_id] = {							\
    389 		.type = SUNXI_CCU_FRACTIONAL,				\
    390 		.base.name = (_name),					\
    391 		.u.fractional.reg = (_reg),				\
    392 		.u.fractional.parent = (_parent),			\
    393 		.u.fractional.m = (_m),					\
    394 		.u.fractional.m_min = (_m_min),				\
    395 		.u.fractional.m_max = (_m_max),				\
    396 		.u.fractional.prediv = (_prediv),			\
    397 		.u.fractional.div_en = (_div_en),			\
    398 		.u.fractional.frac_sel = (_frac_sel),			\
    399 		.u.fractional.frac[0] = (_frac0),			\
    400 		.u.fractional.frac[1] = (_frac1),			\
    401 		.u.fractional.enable = (_enable),			\
    402 		.enable = sunxi_ccu_fractional_enable,			\
    403 		.get_rate = sunxi_ccu_fractional_get_rate,		\
    404 		.set_rate = sunxi_ccu_fractional_set_rate,		\
    405 		.round_rate = sunxi_ccu_fractional_round_rate,		\
    406 		.get_parent = sunxi_ccu_fractional_get_parent,		\
    407 	}
    408 
    409 struct sunxi_ccu_clk {
    410 	struct clk	base;
    411 	enum sunxi_ccu_clktype type;
    412 	union {
    413 		struct sunxi_ccu_gate gate;
    414 		struct sunxi_ccu_nm nm;
    415 		struct sunxi_ccu_nkmp nkmp;
    416 		struct sunxi_ccu_prediv prediv;
    417 		struct sunxi_ccu_div div;
    418 		struct sunxi_ccu_phase phase;
    419 		struct sunxi_ccu_fixed_factor fixed_factor;
    420 		struct sunxi_ccu_fractional fractional;
    421 	} u;
    422 
    423 	int		(*enable)(struct sunxi_ccu_softc *,
    424 				  struct sunxi_ccu_clk *, int);
    425 	u_int		(*get_rate)(struct sunxi_ccu_softc *,
    426 				    struct sunxi_ccu_clk *);
    427 	int		(*set_rate)(struct sunxi_ccu_softc *,
    428 				    struct sunxi_ccu_clk *, u_int);
    429 	u_int		(*round_rate)(struct sunxi_ccu_softc *,
    430 				    struct sunxi_ccu_clk *, u_int);
    431 	const char *	(*get_parent)(struct sunxi_ccu_softc *,
    432 				      struct sunxi_ccu_clk *);
    433 	int		(*set_parent)(struct sunxi_ccu_softc *,
    434 				      struct sunxi_ccu_clk *,
    435 				      const char *);
    436 };
    437 
    438 struct sunxi_ccu_softc {
    439 	device_t		sc_dev;
    440 	int			sc_phandle;
    441 	bus_space_tag_t		sc_bst;
    442 	bus_space_handle_t	sc_bsh;
    443 
    444 	struct clk_domain	sc_clkdom;
    445 
    446 	struct sunxi_ccu_reset *sc_resets;
    447 	u_int			sc_nresets;
    448 
    449 	struct sunxi_ccu_clk	*sc_clks;
    450 	u_int			sc_nclks;
    451 };
    452 
    453 int	sunxi_ccu_attach(struct sunxi_ccu_softc *);
    454 struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *,
    455 					   const char *);
    456 void	sunxi_ccu_print(struct sunxi_ccu_softc *);
    457 
    458 #define CCU_READ(sc, reg)	\
    459 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
    460 #define CCU_WRITE(sc, reg, val)	\
    461 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
    462 
    463 #endif /* _ARM_SUNXI_CCU_H */
    464