1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/kernel.h>
19#include <linux/types.h>
20#include <linux/errno.h>
21#include <linux/err.h>
22#include <linux/io.h>
23
24#include "clockdomain.h"
25#include "cm.h"
26#include "cm1_44xx.h"
27#include "cm2_44xx.h"
28#include "cm44xx.h"
29#include "cm-regbits-34xx.h"
30#include "prcm44xx.h"
31#include "prm44xx.h"
32#include "prcm_mpu44xx.h"
33#include "prcm-common.h"
34
35#define OMAP4430_IDLEST_SHIFT 16
36#define OMAP4430_IDLEST_MASK (0x3 << 16)
37#define OMAP4430_CLKTRCTRL_SHIFT 0
38#define OMAP4430_CLKTRCTRL_MASK (0x3 << 0)
39#define OMAP4430_MODULEMODE_SHIFT 0
40#define OMAP4430_MODULEMODE_MASK (0x3 << 0)
41
42
43
44
45
46
47
48
49
50
51
52
53#define CLKCTRL_IDLEST_FUNCTIONAL 0x0
54#define CLKCTRL_IDLEST_INTRANSITION 0x1
55#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
56#define CLKCTRL_IDLEST_DISABLED 0x3
57
58static struct omap_domain_base _cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
59
60
61
62
63
64
65
66static void omap_cm_base_init(void)
67{
68 memcpy(&_cm_bases[OMAP4430_PRM_PARTITION], &prm_base, sizeof(prm_base));
69 memcpy(&_cm_bases[OMAP4430_CM1_PARTITION], &cm_base, sizeof(cm_base));
70 memcpy(&_cm_bases[OMAP4430_CM2_PARTITION], &cm2_base, sizeof(cm2_base));
71 memcpy(&_cm_bases[OMAP4430_PRCM_MPU_PARTITION], &prcm_mpu_base,
72 sizeof(prcm_mpu_base));
73}
74
75
76
77static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
78
79
80
81
82
83
84
85
86
87
88static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs)
89{
90 u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
91 v &= OMAP4430_IDLEST_MASK;
92 v >>= OMAP4430_IDLEST_SHIFT;
93 return v;
94}
95
96
97
98
99
100
101
102
103
104
105static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs)
106{
107 u32 v;
108
109 v = _clkctrl_idlest(part, inst, clkctrl_offs);
110
111 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
112 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
113}
114
115
116static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
117{
118 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
119 part == OMAP4430_INVALID_PRCM_PARTITION ||
120 !_cm_bases[part].va);
121 return readl_relaxed(_cm_bases[part].va + inst + idx);
122}
123
124
125static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
126{
127 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
128 part == OMAP4430_INVALID_PRCM_PARTITION ||
129 !_cm_bases[part].va);
130 writel_relaxed(val, _cm_bases[part].va + inst + idx);
131}
132
133
134static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
135 s16 idx)
136{
137 u32 v;
138
139 v = omap4_cminst_read_inst_reg(part, inst, idx);
140 v &= ~mask;
141 v |= bits;
142 omap4_cminst_write_inst_reg(v, part, inst, idx);
143
144 return v;
145}
146
147static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
148{
149 return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
150}
151
152static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
153 s16 idx)
154{
155 return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
156}
157
158static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
159{
160 u32 v;
161
162 v = omap4_cminst_read_inst_reg(part, inst, idx);
163 v &= mask;
164 v >>= __ffs(mask);
165
166 return v;
167}
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs)
184{
185 u32 v;
186
187 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
188 v &= ~OMAP4430_CLKTRCTRL_MASK;
189 v |= c << OMAP4430_CLKTRCTRL_SHIFT;
190 omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
191}
192
193
194
195
196
197
198
199
200
201
202static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
203{
204 u32 v;
205
206 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
207 v &= OMAP4430_CLKTRCTRL_MASK;
208 v >>= OMAP4430_CLKTRCTRL_SHIFT;
209
210 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
211}
212
213
214
215
216
217
218
219
220
221
222static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
223{
224 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
225}
226
227
228
229
230
231
232
233
234
235
236
237static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
238{
239 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
240}
241
242
243
244
245
246
247
248
249
250
251static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
252{
253 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
254}
255
256
257
258
259
260static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
261{
262 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs);
263}
264
265
266
267
268
269
270
271
272
273
274
275
276
277static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
278 u8 bit_shift)
279{
280 int i = 0;
281
282 omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs),
283 MAX_MODULE_READY_TIME, i);
284
285 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
286}
287
288
289
290
291
292
293
294
295
296
297
298
299
300static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
301 u8 bit_shift)
302{
303 int i = 0;
304
305 omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) ==
306 CLKCTRL_IDLEST_DISABLED),
307 MAX_MODULE_DISABLE_TIME, i);
308
309 return (i < MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY;
310}
311
312
313
314
315
316
317
318
319
320
321static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
322 u16 clkctrl_offs)
323{
324 u32 v;
325
326 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
327 v &= ~OMAP4430_MODULEMODE_MASK;
328 v |= mode << OMAP4430_MODULEMODE_SHIFT;
329 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
330}
331
332
333
334
335
336
337
338
339
340static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
341{
342 u32 v;
343
344 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
345 v &= ~OMAP4430_MODULEMODE_MASK;
346 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
347}
348
349
350
351
352
353static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
354 struct clockdomain *clkdm2)
355{
356 omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
357 clkdm1->prcm_partition,
358 clkdm1->cm_inst, clkdm1->clkdm_offs +
359 OMAP4_CM_STATICDEP);
360 return 0;
361}
362
363static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
364 struct clockdomain *clkdm2)
365{
366 omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
367 clkdm1->prcm_partition,
368 clkdm1->cm_inst, clkdm1->clkdm_offs +
369 OMAP4_CM_STATICDEP);
370 return 0;
371}
372
373static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
374 struct clockdomain *clkdm2)
375{
376 return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
377 clkdm1->cm_inst,
378 clkdm1->clkdm_offs +
379 OMAP4_CM_STATICDEP,
380 (1 << clkdm2->dep_bit));
381}
382
383static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
384{
385 struct clkdm_dep *cd;
386 u32 mask = 0;
387
388 if (!clkdm->prcm_partition)
389 return 0;
390
391 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
392 if (!cd->clkdm)
393 continue;
394
395 mask |= 1 << cd->clkdm->dep_bit;
396 cd->wkdep_usecount = 0;
397 }
398
399 omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
400 clkdm->cm_inst, clkdm->clkdm_offs +
401 OMAP4_CM_STATICDEP);
402 return 0;
403}
404
405static int omap4_clkdm_sleep(struct clockdomain *clkdm)
406{
407 if (clkdm->flags & CLKDM_CAN_HWSUP)
408 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
409 clkdm->cm_inst,
410 clkdm->clkdm_offs);
411 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
412 omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
413 clkdm->cm_inst,
414 clkdm->clkdm_offs);
415 else
416 return -EINVAL;
417
418 return 0;
419}
420
421static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
422{
423 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
424 clkdm->cm_inst, clkdm->clkdm_offs);
425 return 0;
426}
427
428static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
429{
430 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
431 clkdm->cm_inst, clkdm->clkdm_offs);
432}
433
434static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
435{
436 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
437 omap4_clkdm_wakeup(clkdm);
438 else
439 omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
440 clkdm->cm_inst,
441 clkdm->clkdm_offs);
442}
443
444static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
445{
446 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
447 return omap4_clkdm_wakeup(clkdm);
448
449 return 0;
450}
451
452static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
453{
454 bool hwsup = false;
455
456 if (!clkdm->prcm_partition)
457 return 0;
458
459
460
461
462
463
464 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
465 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
466 omap4_clkdm_allow_idle(clkdm);
467 return 0;
468 }
469
470 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
471 clkdm->cm_inst, clkdm->clkdm_offs);
472
473 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
474 omap4_clkdm_sleep(clkdm);
475
476 return 0;
477}
478
479static u32 omap4_cminst_xlate_clkctrl(u8 part, u16 inst, u16 offset)
480{
481 return _cm_bases[part].pa + inst + offset;
482}
483
484
485
486
487
488
489
490static int omap4_clkdm_save_context(struct clockdomain *clkdm)
491{
492 clkdm->context = omap4_cminst_read_inst_reg(clkdm->prcm_partition,
493 clkdm->cm_inst,
494 clkdm->clkdm_offs +
495 OMAP4_CM_CLKSTCTRL);
496 clkdm->context &= OMAP4430_MODULEMODE_MASK;
497 return 0;
498}
499
500
501
502
503
504
505
506static int omap4_clkdm_restore_context(struct clockdomain *clkdm)
507{
508 switch (clkdm->context) {
509 case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
510 omap4_clkdm_deny_idle(clkdm);
511 break;
512 case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
513 omap4_clkdm_sleep(clkdm);
514 break;
515 case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
516 omap4_clkdm_wakeup(clkdm);
517 break;
518 case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
519 omap4_clkdm_allow_idle(clkdm);
520 break;
521 }
522 return 0;
523}
524
525struct clkdm_ops omap4_clkdm_operations = {
526 .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
527 .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
528 .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
529 .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
530 .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
531 .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
532 .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
533 .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
534 .clkdm_sleep = omap4_clkdm_sleep,
535 .clkdm_wakeup = omap4_clkdm_wakeup,
536 .clkdm_allow_idle = omap4_clkdm_allow_idle,
537 .clkdm_deny_idle = omap4_clkdm_deny_idle,
538 .clkdm_clk_enable = omap4_clkdm_clk_enable,
539 .clkdm_clk_disable = omap4_clkdm_clk_disable,
540 .clkdm_save_context = omap4_clkdm_save_context,
541 .clkdm_restore_context = omap4_clkdm_restore_context,
542};
543
544struct clkdm_ops am43xx_clkdm_operations = {
545 .clkdm_sleep = omap4_clkdm_sleep,
546 .clkdm_wakeup = omap4_clkdm_wakeup,
547 .clkdm_allow_idle = omap4_clkdm_allow_idle,
548 .clkdm_deny_idle = omap4_clkdm_deny_idle,
549 .clkdm_clk_enable = omap4_clkdm_clk_enable,
550 .clkdm_clk_disable = omap4_clkdm_clk_disable,
551};
552
553static const struct cm_ll_data omap4xxx_cm_ll_data = {
554 .wait_module_ready = &omap4_cminst_wait_module_ready,
555 .wait_module_idle = &omap4_cminst_wait_module_idle,
556 .module_enable = &omap4_cminst_module_enable,
557 .module_disable = &omap4_cminst_module_disable,
558 .xlate_clkctrl = &omap4_cminst_xlate_clkctrl,
559};
560
561int __init omap4_cm_init(const struct omap_prcm_init_data *data)
562{
563 omap_cm_base_init();
564
565 return cm_register(&omap4xxx_cm_ll_data);
566}
567
568static void __exit omap4_cm_exit(void)
569{
570 cm_unregister(&omap4xxx_cm_ll_data);
571}
572__exitcall(omap4_cm_exit);
573