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