1 /*-
2 * Copyright (c) 2017 Emmanuel Vadot <[email protected]>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #ifndef __AW_CLK_H__
30 #define __AW_CLK_H__
31
32 /*
33 Allwinner clocks formula :
34
35 PLLs:
36
37 (24MHz*N*K)/(M*P)
38 (24MHz*N)/(M*P)
39 (24MHz*N*2)/M
40 (24MHz*N)/M
41 (24MHz*N*K)/M
42 (24MHz*N*K/2)
43 (24MHz*N)/M
44 (24MHz*N*K/2)
45 (24MHz*N)/M
46
47 Periph clocks:
48
49 Clock Source/Divider N/Divider M
50 Clock Source/Divider N/Divider M/2
51 Clock Source*N/(Divider M+1)/(Divider P+1)
52
53 */
54
55 struct aw_clk_init {
56 const char *name;
57 const char *parent_name;
58 uint64_t default_freq;
59 bool enable;
60 };
61
62 #define AW_CLK_HAS_GATE 0x0001
63 #define AW_CLK_HAS_LOCK 0x0002
64 #define AW_CLK_HAS_MUX 0x0004
65 #define AW_CLK_REPARENT 0x0008
66 #define AW_CLK_SCALE_CHANGE 0x0010
67 #define AW_CLK_HAS_UPDATE 0x0040
68 #define AW_CLK_HAS_PREDIV 0x0080
69
70 #define AW_CLK_FACTOR_POWER_OF_TWO 0x0001
71 #define AW_CLK_FACTOR_ZERO_BASED 0x0002
72 #define AW_CLK_FACTOR_HAS_COND 0x0004
73 #define AW_CLK_FACTOR_FIXED 0x0008
74 #define AW_CLK_FACTOR_ZERO_IS_ONE 0x0010
75
76 struct aw_clk_factor {
77 uint32_t shift; /* Shift bits for the factor */
78 uint32_t mask; /* Mask to get the factor, will be override by the clk methods */
79 uint32_t width; /* Number of bits for the factor */
80 uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */
81
82 uint32_t cond_shift;
83 uint32_t cond_mask;
84 uint32_t cond_width;
85 uint32_t cond_value;
86
87 uint32_t flags; /* Flags */
88 };
89
90 struct aw_clk_frac {
91 uint64_t freq0;
92 uint64_t freq1;
93 uint32_t mode_sel;
94 uint32_t freq_sel;
95 };
96
97 static inline uint32_t
aw_clk_get_factor(uint32_t val,struct aw_clk_factor * factor)98 aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
99 {
100 uint32_t factor_val;
101 uint32_t cond;
102
103 if (factor->flags & AW_CLK_FACTOR_HAS_COND) {
104 cond = (val & factor->cond_mask) >> factor->cond_shift;
105 if (cond != factor->cond_value)
106 return (1);
107 }
108
109 if (factor->flags & AW_CLK_FACTOR_FIXED)
110 return (factor->value);
111
112 factor_val = (val & factor->mask) >> factor->shift;
113 if (factor_val == 0 && (factor->flags & AW_CLK_FACTOR_ZERO_IS_ONE))
114 factor_val = 1;
115
116 if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
117 factor_val = 1 << factor_val;
118 else if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED))
119 factor_val += 1;
120
121 return (factor_val);
122 }
123
124 static inline uint32_t
aw_clk_factor_get_max(struct aw_clk_factor * factor)125 aw_clk_factor_get_max(struct aw_clk_factor *factor)
126 {
127 uint32_t max;
128
129 if (factor->flags & AW_CLK_FACTOR_FIXED)
130 max = factor->value;
131 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
132 max = 1 << ((1 << factor->width) - 1);
133 else {
134 max = (1 << factor->width);
135 }
136
137 return (max);
138 }
139
140 static inline uint32_t
aw_clk_factor_get_min(struct aw_clk_factor * factor)141 aw_clk_factor_get_min(struct aw_clk_factor *factor)
142 {
143 uint32_t min;
144
145 if (factor->flags & AW_CLK_FACTOR_FIXED)
146 min = factor->value;
147 else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
148 min = 0;
149 else
150 min = 1;
151
152 return (min);
153 }
154
155 static inline uint32_t
aw_clk_factor_get_value(struct aw_clk_factor * factor,uint32_t raw)156 aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw)
157 {
158 uint32_t val;
159
160 if (factor->flags & AW_CLK_FACTOR_FIXED)
161 return (factor->value);
162
163 if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
164 val = raw;
165 else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) {
166 for (val = 0; raw != 1; val++)
167 raw >>= 1;
168 } else
169 val = raw - 1;
170
171 return (val);
172 }
173
174 #define CCU_RESET(idx, o, s) \
175 [idx] = { \
176 .offset = o, \
177 .shift = s, \
178 },
179
180 #define CCU_GATE(idx, clkname, pname, o, s) \
181 [idx] = { \
182 .name = clkname, \
183 .parent_name = pname, \
184 .offset = o, \
185 .shift = s, \
186 },
187
188 #define NKMP_CLK(_clkname, _id, _name, _pnames, \
189 _offset, \
190 _n_shift, _n_width, _n_value, _n_flags, \
191 _k_shift, _k_width, _k_value, _k_flags, \
192 _m_shift, _m_width, _m_value, _m_flags, \
193 _p_shift, _p_width, _p_value, _p_flags, \
194 _gate, \
195 _lock, _lock_retries, \
196 _flags) \
197 static struct aw_clk_nkmp_def _clkname = { \
198 .clkdef = { \
199 .id = _id, \
200 .name = _name, \
201 .parent_names = _pnames, \
202 .parent_cnt = nitems(_pnames), \
203 }, \
204 .offset = _offset, \
205 .n.shift = _n_shift, \
206 .n.width = _n_width, \
207 .n.value = _n_value, \
208 .n.flags = _n_flags, \
209 .k.shift = _k_shift, \
210 .k.width = _k_width, \
211 .k.value = _k_value, \
212 .k.flags = _k_flags, \
213 .m.shift = _m_shift, \
214 .m.width = _m_width, \
215 .m.value = _m_value, \
216 .m.flags = _m_flags, \
217 .p.shift = _p_shift, \
218 .p.width = _p_width, \
219 .p.value = _p_value, \
220 .p.flags = _p_flags, \
221 .gate_shift = _gate, \
222 .lock_shift = _lock, \
223 .lock_retries = _lock_retries, \
224 .flags = _flags, \
225 }
226
227 #define NKMP_CLK_WITH_MUX(_clkname, \
228 _id, _name, _pnames, \
229 _offset, \
230 _n_shift, _n_width, _n_value, _n_flags, \
231 _k_shift, _k_width, _k_value, _k_flags, \
232 _m_shift, _m_width, _m_value, _m_flags, \
233 _p_shift, _p_width, _p_value, _p_flags, \
234 _mux_shift, _mux_width, _gate, \
235 _lock, _lock_retries, \
236 _flags) \
237 static struct aw_clk_nkmp_def _clkname = { \
238 .clkdef = { \
239 .id = _id, \
240 .name = _name, \
241 .parent_names = _pnames, \
242 .parent_cnt = nitems(_pnames), \
243 }, \
244 .offset = _offset, \
245 .n.shift = _n_shift, \
246 .n.width = _n_width, \
247 .n.value = _n_value, \
248 .n.flags = _n_flags, \
249 .k.shift = _k_shift, \
250 .k.width = _k_width, \
251 .k.value = _k_value, \
252 .k.flags = _k_flags, \
253 .m.shift = _m_shift, \
254 .m.width = _m_width, \
255 .m.value = _m_value, \
256 .m.flags = _m_flags, \
257 .p.shift = _p_shift, \
258 .p.width = _p_width, \
259 .p.value = _p_value, \
260 .p.flags = _p_flags, \
261 .mux_shift = _mux_shift, \
262 .mux_width = _mux_width, \
263 .gate_shift = _gate, \
264 .lock_shift = _lock, \
265 .lock_retries = _lock_retries, \
266 .flags = _flags, \
267 }
268
269 #define NKMP_CLK_WITH_UPDATE(_clkname, \
270 _id, _name, _pnames, \
271 _offset, \
272 _n_shift, _n_width, _n_value, _n_flags, \
273 _k_shift, _k_width, _k_value, _k_flags, \
274 _m_shift, _m_width, _m_value, _m_flags, \
275 _p_shift, _p_width, _p_value, _p_flags, \
276 _gate, \
277 _lock, _lock_retries, \
278 _update, \
279 _flags) \
280 static struct aw_clk_nkmp_def _clkname = { \
281 .clkdef = { \
282 .id = _id, \
283 .name = _name, \
284 .parent_names = _pnames, \
285 .parent_cnt = nitems(_pnames), \
286 }, \
287 .offset = _offset, \
288 .n.shift = _n_shift, \
289 .n.width = _n_width, \
290 .n.value = _n_value, \
291 .n.flags = _n_flags, \
292 .k.shift = _k_shift, \
293 .k.width = _k_width, \
294 .k.value = _k_value, \
295 .k.flags = _k_flags, \
296 .m.shift = _m_shift, \
297 .m.width = _m_width, \
298 .m.value = _m_value, \
299 .m.flags = _m_flags, \
300 .p.shift = _p_shift, \
301 .p.width = _p_width, \
302 .p.value = _p_value, \
303 .p.flags = _p_flags, \
304 .gate_shift = _gate, \
305 .lock_shift = _lock, \
306 .lock_retries = _lock_retries, \
307 .update_shift = _update, \
308 .flags = _flags | AW_CLK_HAS_UPDATE, \
309 }
310
311 #define FRAC_CLK(_clkname, _id, _name, _pnames, \
312 _offset, \
313 _nshift, _nwidth, _nvalue, _nflags, \
314 _mshift, _mwidth, _mvalue, _mflags, \
315 _gate_shift, _lock_shift,_lock_retries, \
316 _flags, _freq0, _freq1, _mode_sel, _freq_sel) \
317 static struct aw_clk_frac_def _clkname = { \
318 .clkdef = { \
319 .id = _id, \
320 .name = _name, \
321 .parent_names = _pnames, \
322 .parent_cnt = nitems(_pnames), \
323 }, \
324 .offset = _offset, \
325 .n.shift = _nshift, \
326 .n.width = _nwidth, \
327 .n.value = _nvalue, \
328 .n.flags = _nflags, \
329 .m.shift = _mshift, \
330 .m.width = _mwidth, \
331 .m.value = _mvalue, \
332 .m.flags = _mflags, \
333 .gate_shift = _gate_shift, \
334 .lock_shift = _lock_shift, \
335 .lock_retries = _lock_retries, \
336 .flags = _flags, \
337 .frac.freq0 = _freq0, \
338 .frac.freq1 = _freq1, \
339 .frac.mode_sel = _mode_sel, \
340 .frac.freq_sel = _freq_sel, \
341 }
342
343 #define NM_CLK(_clkname, _id, _name, _pnames, \
344 _offset, \
345 _nshift, _nwidth, _nvalue, _nflags, \
346 _mshift, _mwidth, _mvalue, _mflags, \
347 _mux_shift, _mux_width, \
348 _gate_shift, \
349 _flags) \
350 static struct aw_clk_nm_def _clkname = { \
351 .clkdef = { \
352 .id = _id, \
353 .name = _name, \
354 .parent_names = _pnames, \
355 .parent_cnt = nitems(_pnames), \
356 }, \
357 .offset = _offset, \
358 .n.shift = _nshift, \
359 .n.width = _nwidth, \
360 .n.value = _nvalue, \
361 .n.flags = _nflags, \
362 .mux_shift = _mux_shift, \
363 .m.shift = _mshift, \
364 .m.width = _mwidth, \
365 .m.value = _mvalue, \
366 .m.flags = _mflags, \
367 .mux_width = _mux_width, \
368 .gate_shift = _gate_shift, \
369 .flags = _flags, \
370 }
371
372 #define PREDIV_CLK(_clkname, _id, _name, _pnames, \
373 _offset, \
374 _mux_shift, _mux_width, \
375 _div_shift, _div_width, _div_value, _div_flags, \
376 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
377 _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \
378 static struct aw_clk_prediv_mux_def _clkname = { \
379 .clkdef = { \
380 .id = _id, \
381 .name = _name, \
382 .parent_names = _pnames, \
383 .parent_cnt = nitems(_pnames), \
384 }, \
385 .offset = _offset, \
386 .mux_shift = _mux_shift, \
387 .mux_width = _mux_width, \
388 .div.shift = _div_shift, \
389 .div.width = _div_width, \
390 .div.value = _div_value, \
391 .div.flags = _div_flags, \
392 .prediv.shift = _prediv_shift, \
393 .prediv.width = _prediv_width, \
394 .prediv.value = _prediv_value, \
395 .prediv.flags = _prediv_flags, \
396 .prediv.cond_shift = _prediv_cond_shift, \
397 .prediv.cond_width = _prediv_cond_width, \
398 .prediv.cond_value = _prediv_cond_value, \
399 }
400
401 #define PREDIV_CLK_WITH_MASK(_clkname, _id, _name, _pnames, \
402 _offset, \
403 _mux_shift, _mux_width, \
404 _div_shift, _div_width, _div_value, _div_flags, \
405 _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
406 _prediv_cond_mask, _prediv_cond_value) \
407 static struct aw_clk_prediv_mux_def _clkname = { \
408 .clkdef = { \
409 .id = _id, \
410 .name = _name, \
411 .parent_names = _pnames, \
412 .parent_cnt = nitems(_pnames), \
413 }, \
414 .offset = _offset, \
415 .mux_shift = _mux_shift, \
416 .mux_width = _mux_width, \
417 .div.shift = _div_shift, \
418 .div.width = _div_width, \
419 .div.value = _div_value, \
420 .div.flags = _div_flags, \
421 .prediv.shift = _prediv_shift, \
422 .prediv.width = _prediv_width, \
423 .prediv.value = _prediv_value, \
424 .prediv.flags = _prediv_flags, \
425 .prediv.cond_shift = 0, \
426 .prediv.cond_width = 0, \
427 .prediv.cond_mask = _prediv_cond_mask, \
428 .prediv.cond_value = _prediv_cond_value, \
429 }
430
431 #define MUX_CLK(_clkname, _id, _name, _pnames, \
432 _offset, _shift, _width) \
433 static struct clk_mux_def _clkname = { \
434 .clkdef = { \
435 .id = _id, \
436 .name = _name, \
437 .parent_names = _pnames, \
438 .parent_cnt = nitems(_pnames) \
439 }, \
440 .offset = _offset, \
441 .shift = _shift, \
442 .width = _width, \
443 }
444
445 #define DIV_CLK(_clkname, _id, _name, _pnames, \
446 _offset, \
447 _i_shift, _i_width, \
448 _div_flags, _div_table) \
449 static struct clk_div_def _clkname = { \
450 .clkdef = { \
451 .id = _id, \
452 .name = _name, \
453 .parent_names = _pnames, \
454 .parent_cnt = nitems(_pnames) \
455 }, \
456 .offset = _offset, \
457 .i_shift = _i_shift, \
458 .i_width = _i_width, \
459 .div_flags = _div_flags, \
460 .div_table = _div_table, \
461 }
462
463 #define FIXED_CLK(_clkname, _id, _name, _pnames, \
464 _freq, _mult, _div, _flags) \
465 static struct clk_fixed_def _clkname = { \
466 .clkdef = { \
467 .id = _id, \
468 .name = _name, \
469 .parent_names = _pnames, \
470 .parent_cnt = 1, \
471 }, \
472 .freq = _freq, \
473 .mult = _mult, \
474 .div = _div, \
475 .fixed_flags = _flags, \
476 }
477
478 #endif /* __AW_CLK_H__ */
479