xref: /freebsd/sys/dev/clk/spacemit/k1_clk.h (revision dcb10e3add17259715352885dfc55ca92061d2ed)
1*dcb10e3aSBojan Novković /*
2*dcb10e3aSBojan Novković  * Copyright (c) 2026 Bojan Novković <bnovkov@FreeBSD.org>
3*dcb10e3aSBojan Novković  *
4*dcb10e3aSBojan Novković  * SPDX-License-Identifier: BSD-2-Clause
5*dcb10e3aSBojan Novković  */
6*dcb10e3aSBojan Novković 
7*dcb10e3aSBojan Novković 
8*dcb10e3aSBojan Novković /*
9*dcb10e3aSBojan Novković  * Common helper macros for the Spacemit K1 SoC clocks.
10*dcb10e3aSBojan Novković  */
11*dcb10e3aSBojan Novković 
12*dcb10e3aSBojan Novković #ifndef _K1_CLK_H_
13*dcb10e3aSBojan Novković #define	_K1_CLK_H_
14*dcb10e3aSBojan Novković 
15*dcb10e3aSBojan Novković #include <dev/clk/clk.h>
16*dcb10e3aSBojan Novković 
17*dcb10e3aSBojan Novković /*
18*dcb10e3aSBojan Novković  * Helper macro to count the number of parent clocks passed
19*dcb10e3aSBojan Novković  * to the K1_CLK_COMMON macro. The maximum number of parents
20*dcb10e3aSBojan Novković  * for the K1 clocks is 8.
21*dcb10e3aSBojan Novković  */
22*dcb10e3aSBojan Novković #define _K1_CLK_PARENT_CNT_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
23*dcb10e3aSBojan Novković #define K1_CLK_PARENT_CNT(...) _K1_CLK_PARENT_CNT_IMPL(_, ## __VA_ARGS__, 8, \
24*dcb10e3aSBojan Novković     7, 6, 5, 4, 3, 2, 1, 0)
25*dcb10e3aSBojan Novković 
26*dcb10e3aSBojan Novković #define K1_CLK_COMMON(_clkname, _id, ...)			\
27*dcb10e3aSBojan Novković 	.clkdef = {						\
28*dcb10e3aSBojan Novković 	.id = _id,						\
29*dcb10e3aSBojan Novković 	.name = #_clkname,					\
30*dcb10e3aSBojan Novković 	.parent_names = (const char*[]) { __VA_ARGS__ },	\
31*dcb10e3aSBojan Novković 	.parent_cnt = K1_CLK_PARENT_CNT(__VA_ARGS__),		\
32*dcb10e3aSBojan Novković }
33*dcb10e3aSBojan Novković 
34*dcb10e3aSBojan Novković #define K1_CLK_GATE(_clkname, _id, _reg, _gate_bit, ...)	\
35*dcb10e3aSBojan Novković 	{							\
36*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),		\
37*dcb10e3aSBojan Novković 	.reg = _reg,						\
38*dcb10e3aSBojan Novković 	.gate_mask = 1 << _gate_bit,				\
39*dcb10e3aSBojan Novković }
40*dcb10e3aSBojan Novković 
41*dcb10e3aSBojan Novković #define K1_CLK_DIV(_clkname, _id, _reg, _div_bits, _div_shift,	\
42*dcb10e3aSBojan Novković    _fc_bit, ...)						\
43*dcb10e3aSBojan Novković 	{							\
44*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),		\
45*dcb10e3aSBojan Novković 	.reg = _reg,						\
46*dcb10e3aSBojan Novković 	.div_nbits = _div_bits,					\
47*dcb10e3aSBojan Novković 	.div_shift = _div_shift,				\
48*dcb10e3aSBojan Novković 	.fc_mask = 1 << _fc_bit,				\
49*dcb10e3aSBojan Novković }
50*dcb10e3aSBojan Novković 
51*dcb10e3aSBojan Novković #define K1_CLK_DIV_MUX(_clkname, _id, _reg, _div_bits,	\
52*dcb10e3aSBojan Novković     _div_shift, _mux_nbits, _mux_shift, _fc_bit, ...)	\
53*dcb10e3aSBojan Novković 	{						\
54*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),	\
55*dcb10e3aSBojan Novković 	.reg = _reg,					\
56*dcb10e3aSBojan Novković 	.div_nbits = _div_bits,				\
57*dcb10e3aSBojan Novković 	.div_shift = _div_shift,			\
58*dcb10e3aSBojan Novković 	.mux_nbits = _mux_nbits,			\
59*dcb10e3aSBojan Novković 	.mux_shift = _mux_shift,			\
60*dcb10e3aSBojan Novković 	.fc_mask =  1 <<_fc_bit,			\
61*dcb10e3aSBojan Novković }
62*dcb10e3aSBojan Novković 
63*dcb10e3aSBojan Novković #define K1_CLK_DIV_GATE(_clkname, _id, _reg, _div_bits, _div_shift,	\
64*dcb10e3aSBojan Novković     _gate_bit, ...)							\
65*dcb10e3aSBojan Novković 	{								\
66*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),			\
67*dcb10e3aSBojan Novković 	.reg = _reg,							\
68*dcb10e3aSBojan Novković 	.gate_mask = (1 << _gate_bit),					\
69*dcb10e3aSBojan Novković 	.div_nbits = _div_bits,						\
70*dcb10e3aSBojan Novković 	.div_shift = _div_shift,					\
71*dcb10e3aSBojan Novković }
72*dcb10e3aSBojan Novković 
73*dcb10e3aSBojan Novković #define K1_CLK_MUX_GATE(_clkname, _id, _reg, _mux_nbits, _mux_shift,	\
74*dcb10e3aSBojan Novković     _gate_bit, ...)							\
75*dcb10e3aSBojan Novković 	{								\
76*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),			\
77*dcb10e3aSBojan Novković 	.reg = _reg,							\
78*dcb10e3aSBojan Novković 	.gate_mask = (1 << _gate_bit),					\
79*dcb10e3aSBojan Novković 	.mux_nbits = _mux_nbits,					\
80*dcb10e3aSBojan Novković 	.mux_shift = _mux_shift,					\
81*dcb10e3aSBojan Novković }
82*dcb10e3aSBojan Novković 
83*dcb10e3aSBojan Novković #define K1_CLK_DIV_MUX_GATE(_clkname, _id, _reg, _div_bits,	\
84*dcb10e3aSBojan Novković     _div_shift, _mux_nbits, _mux_shift,				\
85*dcb10e3aSBojan Novković     _gate_bit, _fc_bit, ...)					\
86*dcb10e3aSBojan Novković 	{							\
87*dcb10e3aSBojan Novković 	K1_CLK_COMMON(_clkname, _id, __VA_ARGS__),		\
88*dcb10e3aSBojan Novković 	.reg = _reg,						\
89*dcb10e3aSBojan Novković 	.gate_mask = (1 << _gate_bit),				\
90*dcb10e3aSBojan Novković 	.div_nbits = _div_bits,					\
91*dcb10e3aSBojan Novković 	.div_shift = _div_shift,				\
92*dcb10e3aSBojan Novković 	.mux_nbits = _mux_nbits,				\
93*dcb10e3aSBojan Novković 	.mux_shift = _mux_shift,				\
94*dcb10e3aSBojan Novković 	.fc_mask =  1 <<_fc_bit,				\
95*dcb10e3aSBojan Novković }
96*dcb10e3aSBojan Novković 
97*dcb10e3aSBojan Novković #define K1_RESET(_id, _reg, _assert_bit, _deassert_bit)	\
98*dcb10e3aSBojan Novković 	[_id] = {					\
99*dcb10e3aSBojan Novković 	.reg = _reg,					\
100*dcb10e3aSBojan Novković 	.assert_mask = (1 << _assert_bit),		\
101*dcb10e3aSBojan Novković 	.deassert_mask = (1 << _deassert_bit),		\
102*dcb10e3aSBojan Novković }
103*dcb10e3aSBojan Novković 
104*dcb10e3aSBojan Novković struct k1_clk_def {
105*dcb10e3aSBojan Novković 	struct clknode_init_def	clkdef;
106*dcb10e3aSBojan Novković 
107*dcb10e3aSBojan Novković 	uint64_t rate; /* Fixed clock frequency. */
108*dcb10e3aSBojan Novković 	uint32_t fixed_div; /* Fixed clock divisor. */
109*dcb10e3aSBojan Novković 	uint32_t reg; /* Control register offset.*/
110*dcb10e3aSBojan Novković 	uint32_t div_nbits; /* Frequency divisor. */
111*dcb10e3aSBojan Novković 	uint32_t div_shift;
112*dcb10e3aSBojan Novković 	uint32_t gate_mask; /* Gate bit. */
113*dcb10e3aSBojan Novković 	uint32_t mux_nbits; /* Multiplexer offset. */
114*dcb10e3aSBojan Novković 	uint32_t mux_shift;
115*dcb10e3aSBojan Novković 	uint32_t fc_mask; /* Frequency change request bit. */
116*dcb10e3aSBojan Novković };
117*dcb10e3aSBojan Novković 
118*dcb10e3aSBojan Novković struct k1_reset_def {
119*dcb10e3aSBojan Novković 	uint32_t reg;
120*dcb10e3aSBojan Novković 	uint32_t assert_mask;
121*dcb10e3aSBojan Novković 	uint32_t deassert_mask;
122*dcb10e3aSBojan Novković };
123*dcb10e3aSBojan Novković 
124*dcb10e3aSBojan Novković struct k1_clkdev_softc {
125*dcb10e3aSBojan Novković 	struct mtx mtx;
126*dcb10e3aSBojan Novković 	struct clkdom *clkdom;
127*dcb10e3aSBojan Novković 	struct resource *res;
128*dcb10e3aSBojan Novković 
129*dcb10e3aSBojan Novković 	const struct k1_clk_def *clks;
130*dcb10e3aSBojan Novković 	const struct k1_reset_def *resets;
131*dcb10e3aSBojan Novković 	int nclks;
132*dcb10e3aSBojan Novković 	int nresets;
133*dcb10e3aSBojan Novković 
134*dcb10e3aSBojan Novković 	/*
135*dcb10e3aSBojan Novković 	 * Allow derived clknode implementations to
136*dcb10e3aSBojan Novković 	 * override the generic K1 clock routines.
137*dcb10e3aSBojan Novković 	 */
138*dcb10e3aSBojan Novković 	clknode_class_t clknode_class;
139*dcb10e3aSBojan Novković };
140*dcb10e3aSBojan Novković 
141*dcb10e3aSBojan Novković DECLARE_CLASS(k1_clkdev_driver);
142*dcb10e3aSBojan Novković DECLARE_CLASS(k1_clknode_class);
143*dcb10e3aSBojan Novković 
144*dcb10e3aSBojan Novković int k1_clk_attach(device_t dev);
145*dcb10e3aSBojan Novković 
146*dcb10e3aSBojan Novković #endif
147