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 "iomap.h"
25#include "common.h"
26#include "clockdomain.h"
27#include "cm.h"
28#include "cm1_44xx.h"
29#include "cm2_44xx.h"
30#include "cm44xx.h"
31#include "cminst44xx.h"
32#include "cm-regbits-34xx.h"
33#include "cm-regbits-44xx.h"
34#include "prcm44xx.h"
35#include "prm44xx.h"
36#include "prcm_mpu44xx.h"
37#include "prcm-common.h"
38
39
40
41
42
43
44
45
46
47
48
49
50#define CLKCTRL_IDLEST_FUNCTIONAL 0x0
51#define CLKCTRL_IDLEST_INTRANSITION 0x1
52#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
53#define CLKCTRL_IDLEST_DISABLED 0x3
54
55static void __iomem *_cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
56
57
58
59
60
61
62
63void omap_cm_base_init(void)
64{
65 _cm_bases[OMAP4430_PRM_PARTITION] = prm_base;
66 _cm_bases[OMAP4430_CM1_PARTITION] = cm_base;
67 _cm_bases[OMAP4430_CM2_PARTITION] = cm2_base;
68 _cm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base;
69}
70
71
72
73
74
75
76
77
78
79
80
81
82
83static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
84{
85 u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
86 v &= OMAP4430_IDLEST_MASK;
87 v >>= OMAP4430_IDLEST_SHIFT;
88 return v;
89}
90
91
92
93
94
95
96
97
98
99
100
101static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
102{
103 u32 v;
104
105 v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs);
106
107 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
108 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
109}
110
111
112
113
114u32 omap4_cminst_read_inst_reg(u8 part, s16 inst, u16 idx)
115{
116 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
117 part == OMAP4430_INVALID_PRCM_PARTITION ||
118 !_cm_bases[part]);
119 return __raw_readl(_cm_bases[part] + inst + idx);
120}
121
122
123void omap4_cminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx)
124{
125 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
126 part == OMAP4430_INVALID_PRCM_PARTITION ||
127 !_cm_bases[part]);
128 __raw_writel(val, _cm_bases[part] + inst + idx);
129}
130
131
132u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
133 s16 idx)
134{
135 u32 v;
136
137 v = omap4_cminst_read_inst_reg(part, inst, idx);
138 v &= ~mask;
139 v |= bits;
140 omap4_cminst_write_inst_reg(v, part, inst, idx);
141
142 return v;
143}
144
145u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx)
146{
147 return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
148}
149
150u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx)
151{
152 return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
153}
154
155u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
156{
157 u32 v;
158
159 v = omap4_cminst_read_inst_reg(part, inst, idx);
160 v &= mask;
161 v >>= __ffs(mask);
162
163 return v;
164}
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180static void _clktrctrl_write(u8 c, u8 part, s16 inst, u16 cdoffs)
181{
182 u32 v;
183
184 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
185 v &= ~OMAP4430_CLKTRCTRL_MASK;
186 v |= c << OMAP4430_CLKTRCTRL_SHIFT;
187 omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
188}
189
190
191
192
193
194
195
196
197
198
199bool omap4_cminst_is_clkdm_in_hwsup(u8 part, s16 inst, u16 cdoffs)
200{
201 u32 v;
202
203 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
204 v &= OMAP4430_CLKTRCTRL_MASK;
205 v >>= OMAP4430_CLKTRCTRL_SHIFT;
206
207 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
208}
209
210
211
212
213
214
215
216
217
218
219void omap4_cminst_clkdm_enable_hwsup(u8 part, s16 inst, u16 cdoffs)
220{
221 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
222}
223
224
225
226
227
228
229
230
231
232
233
234void omap4_cminst_clkdm_disable_hwsup(u8 part, s16 inst, u16 cdoffs)
235{
236 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
237}
238
239
240
241
242
243
244
245
246
247
248void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs)
249{
250 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
251}
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
270 u16 clkctrl_offs)
271{
272 int i = 0;
273
274 if (!clkctrl_offs)
275 return 0;
276
277 omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs),
278 MAX_MODULE_READY_TIME, i);
279
280 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
281}
282
283
284
285
286
287
288
289
290
291
292
293
294
295int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
296{
297 int i = 0;
298
299 if (!clkctrl_offs)
300 return 0;
301
302 omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) ==
303 CLKCTRL_IDLEST_DISABLED),
304 MAX_MODULE_DISABLE_TIME, i);
305
306 return (i < MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY;
307}
308
309
310
311
312
313
314
315
316
317
318
319void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
320 u16 clkctrl_offs)
321{
322 u32 v;
323
324 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
325 v &= ~OMAP4430_MODULEMODE_MASK;
326 v |= mode << OMAP4430_MODULEMODE_SHIFT;
327 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
328}
329
330
331
332
333
334
335
336
337
338
339void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
340 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 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
408 clkdm->cm_inst, clkdm->clkdm_offs);
409 return 0;
410}
411
412static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
413{
414 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
415 clkdm->cm_inst, clkdm->clkdm_offs);
416 return 0;
417}
418
419static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
420{
421 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
422 clkdm->cm_inst, clkdm->clkdm_offs);
423}
424
425static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
426{
427 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
428 omap4_clkdm_wakeup(clkdm);
429 else
430 omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
431 clkdm->cm_inst,
432 clkdm->clkdm_offs);
433}
434
435static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
436{
437 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
438 return omap4_clkdm_wakeup(clkdm);
439
440 return 0;
441}
442
443static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
444{
445 bool hwsup = false;
446
447 if (!clkdm->prcm_partition)
448 return 0;
449
450
451
452
453
454
455 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
456 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
457 omap4_clkdm_allow_idle(clkdm);
458 return 0;
459 }
460
461 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
462 clkdm->cm_inst, clkdm->clkdm_offs);
463
464 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
465 omap4_clkdm_sleep(clkdm);
466
467 return 0;
468}
469
470struct clkdm_ops omap4_clkdm_operations = {
471 .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
472 .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
473 .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
474 .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
475 .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
476 .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
477 .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
478 .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
479 .clkdm_sleep = omap4_clkdm_sleep,
480 .clkdm_wakeup = omap4_clkdm_wakeup,
481 .clkdm_allow_idle = omap4_clkdm_allow_idle,
482 .clkdm_deny_idle = omap4_clkdm_deny_idle,
483 .clkdm_clk_enable = omap4_clkdm_clk_enable,
484 .clkdm_clk_disable = omap4_clkdm_clk_disable,
485};
486