xref: /freebsd/sys/arm/mv/clk/periph.h (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Semihalf.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #ifndef	_PERIPH_H_
30 #define	_PERIPH_H_
31 
32 #include <dev/clk/clk.h>
33 #include <dev/clk/clk_mux.h>
34 #include <dev/clk/clk_div.h>
35 #include <dev/clk/clk_gate.h>
36 
37 #define TBG_SEL                 0x0
38 #define DIV_SEL0                0x4
39 #define DIV_SEL1                0x8
40 #define DIV_SEL2                0xC
41 #define CLK_SEL                 0x10
42 #define CLK_DIS                 0x14
43 #define DIV_MASK		0x7
44 
45 #define MUX_POS			1
46 #define DIV1_POS		2
47 #define DIV2_POS		3
48 #define GATE_POS		4
49 #define FIXED1_POS		5
50 #define FIXED2_POS		6
51 #define CLK_MUX_POS		7
52 
53 #define RD4(_clk, offset, val)			\
54     CLKDEV_READ_4(clknode_get_device(_clk), offset, val)
55 
56 #define A37x0_INTERNAL_CLK_ID(_base, _pos)	\
57     ((_base * 10) + (_pos))
58 
59 #define CLK_FULL_DD(_name, _id, _gate_shift, _tbg_mux_shift,		\
60     _clk_mux_shift, _div1_reg, _div2_reg, _div1_shift, _div2_shift,	\
61     _tbg_mux_name, _div1_name, _div2_name, _clk_mux_name)		\
62 {									\
63 	.type = CLK_FULL_DD,						\
64 	.common_def.device_name = _name,				\
65 	.common_def.device_id = _id,					\
66 	.clk_def.full_dd.tbg_mux.clkdef.name = _tbg_mux_name,		\
67 	.clk_def.full_dd.tbg_mux.offset = TBG_SEL,			\
68 	.clk_def.full_dd.tbg_mux.shift = _tbg_mux_shift,		\
69 	.clk_def.full_dd.tbg_mux.width = 0x2,				\
70 	.clk_def.full_dd.tbg_mux.mux_flags = 0x0,			\
71 	.clk_def.full_dd.div1.clkdef.name = _div1_name,			\
72 	.clk_def.full_dd.div1.offset = _div1_reg,			\
73 	.clk_def.full_dd.div1.i_shift = _div1_shift,			\
74 	.clk_def.full_dd.div1.i_width = 0x3,				\
75 	.clk_def.full_dd.div1.f_shift = 0x0,				\
76 	.clk_def.full_dd.div1.f_width = 0x0,				\
77 	.clk_def.full_dd.div1.div_flags = 0x0,				\
78 	.clk_def.full_dd.div1.div_table = NULL,				\
79 	.clk_def.full_dd.div2.clkdef.name = _div2_name,			\
80 	.clk_def.full_dd.div2.offset = _div2_reg,			\
81 	.clk_def.full_dd.div2.i_shift = _div2_shift,			\
82 	.clk_def.full_dd.div2.i_width = 0x3,				\
83 	.clk_def.full_dd.div2.f_shift = 0x0,				\
84 	.clk_def.full_dd.div2.f_width = 0x0,				\
85 	.clk_def.full_dd.div2.div_flags = 0x0,				\
86 	.clk_def.full_dd.div2.div_table = NULL,				\
87 	.clk_def.full_dd.clk_mux.clkdef.name = _clk_mux_name,		\
88 	.clk_def.full_dd.clk_mux.offset = CLK_SEL,			\
89 	.clk_def.full_dd.clk_mux.shift = _clk_mux_shift,		\
90 	.clk_def.full_dd.clk_mux.width = 0x1,				\
91 	.clk_def.full_dd.clk_mux.mux_flags = 0x0,			\
92 	.clk_def.full_dd.gate.clkdef.name = _name,			\
93 	.clk_def.full_dd.gate.offset = CLK_DIS,				\
94 	.clk_def.full_dd.gate.shift = _gate_shift,			\
95 	.clk_def.full_dd.gate.on_value = 0,				\
96 	.clk_def.full_dd.gate.off_value = 1,				\
97 	.clk_def.full_dd.gate.mask = 0x1,				\
98 	.clk_def.full_dd.gate.gate_flags = 0x0				\
99 }
100 
101 #define CLK_FULL(_name, _id, _gate_shift, _tbg_mux_shift,		\
102     _clk_mux_shift, _div1_reg, _div1_shift, _div_table, _tbg_mux_name,	\
103     _div1_name, _clk_mux_name)						\
104 {									\
105 	.type = CLK_FULL,						\
106 	.common_def.device_name = _name,				\
107 	.common_def.device_id = _id,					\
108 	.clk_def.full_d.tbg_mux.clkdef.name = _tbg_mux_name,		\
109 	.clk_def.full_d.tbg_mux.offset = TBG_SEL,			\
110 	.clk_def.full_d.tbg_mux.shift = _tbg_mux_shift,			\
111 	.clk_def.full_d.tbg_mux.width = 0x2,				\
112 	.clk_def.full_d.tbg_mux.mux_flags = 0x0,			\
113 	.clk_def.full_d.div.clkdef.name = _div1_name,			\
114 	.clk_def.full_d.div.offset = _div1_reg,				\
115 	.clk_def.full_d.div.i_shift = _div1_shift,			\
116 	.clk_def.full_d.div.i_width = 0x3,				\
117 	.clk_def.full_d.div.f_shift = 0x0,				\
118 	.clk_def.full_d.div.f_width = 0x0,				\
119 	.clk_def.full_d.div.div_flags = 0x0,				\
120 	.clk_def.full_d.div.div_table = _div_table,			\
121 	.clk_def.full_d.clk_mux.clkdef.name = _clk_mux_name,		\
122 	.clk_def.full_d.clk_mux.offset = CLK_SEL,			\
123 	.clk_def.full_d.clk_mux.shift = _clk_mux_shift,			\
124 	.clk_def.full_d.clk_mux.width = 0x1,				\
125 	.clk_def.full_d.clk_mux.mux_flags = 0x0,			\
126 	.clk_def.full_d.gate.clkdef.name = _name,			\
127 	.clk_def.full_d.gate.offset = CLK_DIS,				\
128 	.clk_def.full_d.gate.shift = _gate_shift,			\
129 	.clk_def.full_d.gate.on_value = 0,				\
130 	.clk_def.full_d.gate.off_value = 1,				\
131 	.clk_def.full_d.gate.mask = 0x1,				\
132 	.clk_def.full_d.gate.gate_flags = 0x0				\
133 }
134 
135 #define CLK_CPU(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg,	\
136     _div1_shift, _div_table, _tbg_mux_name, _div1_name)			\
137 {									\
138 	.type = CLK_CPU,						\
139 	.common_def.device_name = _name,				\
140 	.common_def.device_id = _id,					\
141 	.clk_def.cpu.tbg_mux.clkdef.name = _tbg_mux_name,		\
142 	.clk_def.cpu.tbg_mux.offset = TBG_SEL,				\
143 	.clk_def.cpu.tbg_mux.shift = _tbg_mux_shift,			\
144 	.clk_def.cpu.tbg_mux.width = 0x2,				\
145 	.clk_def.cpu.tbg_mux.mux_flags = 0x0,				\
146 	.clk_def.cpu.div.clkdef.name = _div1_name,			\
147 	.clk_def.cpu.div.offset = _div1_reg,				\
148 	.clk_def.cpu.div.i_shift = _div1_shift,				\
149 	.clk_def.cpu.div.i_width = 0x3,					\
150 	.clk_def.cpu.div.f_shift = 0x0,					\
151 	.clk_def.cpu.div.f_width = 0x0,					\
152 	.clk_def.cpu.div.div_flags = 0x0,				\
153 	.clk_def.cpu.div.div_table = _div_table,			\
154 	.clk_def.cpu.clk_mux.clkdef.name = _name,			\
155 	.clk_def.cpu.clk_mux.offset = CLK_SEL,				\
156 	.clk_def.cpu.clk_mux.shift = _clk_mux_shift,			\
157 	.clk_def.cpu.clk_mux.width = 0x1,				\
158 	.clk_def.cpu.clk_mux.mux_flags = 0x0,				\
159 }
160 
161 #define CLK_GATE(_name, _id, _gate_shift, _pname)			\
162 {									\
163 	.type = CLK_GATE,						\
164 	.common_def.device_name = _name,				\
165 	.common_def.device_id = _id,					\
166 	.common_def.pname = _pname,					\
167 	.clk_def.gate.gate.clkdef.name = _name,				\
168 	.clk_def.gate.gate.clkdef.parent_cnt = 1,			\
169 	.clk_def.gate.gate.offset = CLK_DIS,				\
170 	.clk_def.gate.gate.shift = _gate_shift,				\
171 	.clk_def.gate.gate.on_value = 0,				\
172 	.clk_def.gate.gate.off_value = 1,				\
173 	.clk_def.gate.gate.mask = 0x1,					\
174 	.clk_def.gate.gate.gate_flags = 0x0				\
175 }
176 
177 #define CLK_MDD(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg,	\
178     _div2_reg, _div1_shift, _div2_shift, _tbg_mux_name, _div1_name,	\
179     _div2_name)								\
180 {									\
181 	.type = CLK_MDD,						\
182 	.common_def.device_name = _name,				\
183 	.common_def.device_id = _id,					\
184 	.clk_def.mdd.tbg_mux.clkdef.name = _tbg_mux_name,		\
185 	.clk_def.mdd.tbg_mux.offset = TBG_SEL,				\
186 	.clk_def.mdd.tbg_mux.shift = _tbg_mux_shift,			\
187 	.clk_def.mdd.tbg_mux.width = 0x2,				\
188 	.clk_def.mdd.tbg_mux.mux_flags = 0x0,				\
189 	.clk_def.mdd.div1.clkdef.name = _div1_name,			\
190 	.clk_def.mdd.div1.offset = _div1_reg,				\
191 	.clk_def.mdd.div1.i_shift = _div1_shift,			\
192 	.clk_def.mdd.div1.i_width = 0x3,				\
193 	.clk_def.mdd.div1.f_shift = 0x0,				\
194 	.clk_def.mdd.div1.f_width = 0x0,				\
195 	.clk_def.mdd.div1.div_flags = 0x0,				\
196 	.clk_def.mdd.div1.div_table = NULL,				\
197 	.clk_def.mdd.div2.clkdef.name = _div2_name,			\
198 	.clk_def.mdd.div2.offset = _div2_reg,				\
199 	.clk_def.mdd.div2.i_shift = _div2_shift,			\
200 	.clk_def.mdd.div2.i_width = 0x3,				\
201 	.clk_def.mdd.div2.f_shift = 0x0,				\
202 	.clk_def.mdd.div2.f_width = 0x0,				\
203 	.clk_def.mdd.div2.div_flags = 0x0,				\
204 	.clk_def.mdd.div2.div_table = NULL,				\
205 	.clk_def.mdd.clk_mux.clkdef.name = _name,			\
206 	.clk_def.mdd.clk_mux.offset = CLK_SEL,				\
207 	.clk_def.mdd.clk_mux.shift = _clk_mux_shift,			\
208 	.clk_def.mdd.clk_mux.width = 0x1,				\
209 	.clk_def.mdd.clk_mux.mux_flags = 0x0				\
210 }
211 
212 #define CLK_MUX_GATE(_name, _id, _gate_shift, _mux_shift, _pname,	\
213      _mux_name, _fixed_name)						\
214 {									\
215 	.type = CLK_MUX_GATE,						\
216 	.common_def.device_name = _name,				\
217 	.common_def.device_id = _id,					\
218 	.common_def.pname = _pname,					\
219 	.clk_def.mux_gate.mux.clkdef.name = _mux_name,			\
220 	.clk_def.mux_gate.mux.offset = TBG_SEL,				\
221 	.clk_def.mux_gate.mux.shift = _mux_shift,			\
222 	.clk_def.mux_gate.mux.width = 0x1,				\
223 	.clk_def.mux_gate.mux.mux_flags = 0x0,				\
224 	.clk_def.mux_gate.gate.clkdef.name = _name,			\
225 	.clk_def.mux_gate.gate.offset = CLK_DIS,			\
226 	.clk_def.mux_gate.gate.shift = _gate_shift,			\
227 	.clk_def.mux_gate.gate.on_value = 0,				\
228 	.clk_def.mux_gate.gate.off_value = 1,				\
229 	.clk_def.mux_gate.gate.mask = 0x1,				\
230 	.clk_def.mux_gate.gate.gate_flags = 0x0,			\
231 	.clk_def.mux_gate.fixed.clkdef.name = _fixed_name		\
232 }
233 
234 #define CLK_MUX_GATE_FIXED(_name, _id, _gate_shift, _mux_shift, 	\
235      _mux_name, _gate_name, _fixed1_name)				\
236 {									\
237 	.type = CLK_MUX_GATE_FIXED,					\
238 	.common_def.device_name = _name,				\
239 	.common_def.device_id = _id,					\
240 	.clk_def.mux_gate_fixed.mux.clkdef.name = _mux_name,		\
241 	.clk_def.mux_gate_fixed.mux.offset = TBG_SEL,			\
242 	.clk_def.mux_gate_fixed.mux.shift = _mux_shift,			\
243 	.clk_def.mux_gate_fixed.mux.width = 0x1,			\
244 	.clk_def.mux_gate_fixed.mux.mux_flags = 0x0,			\
245 	.clk_def.mux_gate_fixed.gate.clkdef.name = _gate_name,		\
246 	.clk_def.mux_gate_fixed.gate.offset = CLK_DIS,			\
247 	.clk_def.mux_gate_fixed.gate.shift = _gate_shift,		\
248 	.clk_def.mux_gate_fixed.gate.on_value = 0,			\
249 	.clk_def.mux_gate_fixed.gate.off_value = 1,			\
250 	.clk_def.mux_gate_fixed.gate.mask = 0x1,			\
251 	.clk_def.mux_gate_fixed.gate.gate_flags = 0x0,			\
252 	.clk_def.mux_gate_fixed.fixed1.clkdef.name = _fixed1_name,	\
253 	.clk_def.mux_gate_fixed.fixed2.clkdef.name = _name		\
254 }
255 
256 #define CLK_FIXED(_name, _id, _gate_shift, _mux_shift, _mux_name,	\
257     _fixed_name)							\
258 {									\
259 	.type = CLK_FIXED,						\
260 	.common_def.device_name = _name,				\
261 	.common_def.device_id = _id,					\
262 	.clk_def.fixed.mux.clkdef.name = _mux_name,			\
263 	.clk_def.fixed.mux.offset = TBG_SEL,				\
264 	.clk_def.fixed.mux.shift = _mux_shift,				\
265 	.clk_def.fixed.mux.width = 0x1,					\
266 	.clk_def.fixed.mux.mux_flags = 0x0,				\
267 	.clk_def.fixed.gate.clkdef.name = _name,			\
268 	.clk_def.fixed.gate.offset = CLK_DIS,				\
269 	.clk_def.fixed.gate.shift = _gate_shift,			\
270 	.clk_def.fixed.gate.on_value = 0,				\
271 	.clk_def.fixed.gate.off_value = 1,				\
272 	.clk_def.fixed.gate.mask = 0x1,					\
273 	.clk_def.fixed.gate.gate_flags = 0x0,				\
274 	.clk_def.fixed.fixed.clkdef.name = _fixed_name			\
275 }
276 
277 struct a37x0_periph_clk_softc {
278 	device_t			dev;
279 	struct resource			*res;
280 	struct clkdom			*clkdom;
281 	struct mtx			mtx;
282 	struct a37x0_periph_clknode_def *devices;
283 	int 				device_count;
284 };
285 
286 struct a37x0_periph_clk_dd_def {
287 	struct clk_mux_def 	tbg_mux;
288 	struct clk_div_def	div1;
289 	struct clk_div_def	div2;
290 	struct clk_mux_def	clk_mux;
291 	struct clk_gate_def	gate;
292 };
293 
294 struct a37x0_periph_clk_cpu_def {
295 	struct clk_mux_def 	tbg_mux;
296 	struct clk_div_def	div;
297 	struct clk_mux_def	clk_mux;
298 };
299 
300 struct a37x0_periph_clk_d_def {
301 	struct clk_mux_def 	tbg_mux;
302 	struct clk_div_def	div;
303 	struct clk_mux_def	clk_mux;
304 	struct clk_gate_def	gate;
305 };
306 
307 struct a37x0_periph_clk_fixed_def {
308 	struct clk_mux_def 	mux;
309 	struct clk_fixed_def	fixed;
310 	struct clk_gate_def	gate;
311 };
312 
313 struct a37x0_periph_clk_gate_def {
314 	struct clk_gate_def	gate;
315 };
316 
317 struct a37x0_periph_clk_mux_dd_def {
318 	struct clk_mux_def 	tbg_mux;
319 	struct clk_div_def	div1;
320 	struct clk_div_def	div2;
321 	struct clk_mux_def	clk_mux;
322 };
323 
324 struct a37x0_periph_clk_mux_div_def {
325 	struct clk_mux_def 	mux;
326 	struct clk_div_def	div;
327 };
328 
329 struct a37x0_periph_clk_mux_gate_def {
330 	struct clk_mux_def 	mux;
331 	struct clk_fixed_def	fixed;
332 	struct clk_gate_def	gate;
333 };
334 
335 struct a37x0_periph_clk_mux_gate_fixed_def {
336 	struct clk_fixed_def	fixed1;
337 	struct clk_mux_def 	mux;
338 	struct clk_gate_def	gate;
339 	struct clk_fixed_def	fixed2;
340 };
341 
342 enum a37x0_periph_clk_type {
343 	/* Double divider clock */
344         CLK_FULL_DD,
345 	/* Single divider clock */
346         CLK_FULL,
347 	/* Gate clock */
348         CLK_GATE,
349 	/* Mux, gate clock */
350         CLK_MUX_GATE,
351 	/* CPU clock */
352         CLK_CPU,
353 	/* Clock with fixed frequency divider */
354 	CLK_FIXED,
355 	/* Clock with double divider, without gate */
356 	CLK_MDD,
357 	/* Clock with two fixed frequency dividers */
358 	CLK_MUX_GATE_FIXED
359 };
360 
361 struct a37x0_periph_common_defs {
362 	char		*device_name;
363 	int		device_id;
364 	int		tbg_cnt;
365 	const char	*pname;
366 	const char 	**tbgs;
367 	const char	*xtal;
368 };
369 
370 union a37x0_periph_clocks_defs {
371 	struct a37x0_periph_clk_dd_def full_dd;
372 	struct a37x0_periph_clk_d_def full_d;
373 	struct a37x0_periph_clk_gate_def gate;
374 	struct a37x0_periph_clk_mux_gate_def mux_gate;
375 	struct a37x0_periph_clk_cpu_def cpu;
376 	struct a37x0_periph_clk_fixed_def fixed;
377 	struct a37x0_periph_clk_mux_dd_def mdd;
378 	struct a37x0_periph_clk_mux_gate_fixed_def mux_gate_fixed;
379 };
380 
381 struct a37x0_periph_clknode_def {
382 	enum a37x0_periph_clk_type		type;
383 	struct a37x0_periph_common_defs		common_def;
384 	union a37x0_periph_clocks_defs		clk_def;
385 };
386 
387 int a37x0_periph_create_mux(struct clkdom *,
388     struct clk_mux_def *, int);
389 int a37x0_periph_create_div(struct clkdom *,
390     struct clk_div_def *, int);
391 int a37x0_periph_create_gate(struct clkdom *,
392     struct clk_gate_def *, int);
393 void a37x0_periph_set_props(struct clknode_init_def *, const char **,
394     unsigned int);
395 int a37x0_periph_d_register_full_clk_dd(struct clkdom *,
396     struct a37x0_periph_clknode_def *);
397 int a37x0_periph_d_register_full_clk(struct clkdom *,
398     struct a37x0_periph_clknode_def *);
399 int a37x0_periph_d_register_periph_cpu(struct clkdom *,
400     struct a37x0_periph_clknode_def *);
401 int a37x0_periph_fixed_register_fixed(struct clkdom*,
402     struct a37x0_periph_clknode_def *);
403 int a37x0_periph_gate_register_gate(struct clkdom *,
404     struct a37x0_periph_clknode_def *);
405 int a37x0_periph_d_register_mdd(struct clkdom *,
406     struct a37x0_periph_clknode_def *);
407 int a37x0_periph_d_register_mux_div_clk(struct clkdom *,
408     struct a37x0_periph_clknode_def *);
409 int a37x0_periph_register_mux_gate(struct clkdom *,
410     struct a37x0_periph_clknode_def *);
411 int a37x0_periph_register_mux_gate_fixed(struct clkdom *,
412     struct a37x0_periph_clknode_def *);
413 
414 int a37x0_periph_clk_read_4(device_t, bus_addr_t, uint32_t *);
415 void a37x0_periph_clk_device_unlock(device_t);
416 void a37x0_periph_clk_device_lock(device_t);
417 int a37x0_periph_clk_attach(device_t);
418 int a37x0_periph_clk_detach(device_t);
419 
420 #endif
421